use japi::{ Document, Attributes, ResourceObject, OptionalVec, Relationships, Links, Link, Relationship, GenericObject, }; use serde_derive::{Serialize, Deserialize}; use serde_json::{self, json}; use std::convert::TryInto; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct Article { title: String, } impl Attributes for Article { fn kind() -> String { "articles".into() } fn links(id: &str) -> Option { let mut links = Links::new(); links.insert("self".into(), Link::Url(format!("/articles/{}", id))); Some(links) } } impl Article { fn add_author(article: &mut ResourceObject
, author: &ResourceObject) { let mut links = Links::new(); links.insert("self".into(), Link::Url(format!("/articles/{}/relationships/author", article.id.as_ref().unwrap()))); links.insert("related".into(), Link::Url(format!("/articles/{}/author", article.id.as_ref().unwrap()))); let r = Relationship { links: Some(links), data: OptionalVec::One(Some(author.try_into().unwrap())), ..Default::default() }; article.add_relationship("author".into(), r); } fn add_comments(article: &mut ResourceObject
, comments: &[ResourceObject]) { let mut links = Links::new(); links.insert("self".into(), Link::Url(format!("/articles/{}/relationships/comments", article.id.as_ref().unwrap()))); links.insert("related".into(), Link::Url(format!("/articles/{}/comments", article.id.as_ref().unwrap()))); let r = Relationship { links: Some(links), data: OptionalVec::Many(comments.iter().map(|c| c.try_into().unwrap()).collect()), ..Default::default() }; article.add_relationship("comments".into(), r); } } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[serde(rename_all = "kebab-case")] pub struct People { first_name: String, last_name: String, contact: String, } impl Attributes for People { fn kind() -> String { "people".into() } fn links(id: &str) -> Option { let mut links = Links::new(); links.insert("self".into(), Link::Url(format!("/people/{}", id))); Some(links) } } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct Comment { body: String, } impl Attributes for Comment { fn kind() -> String { "comments".into() } fn links(id: &str) -> Option { let mut links = Links::new(); links.insert("self".into(), Link::Url(format!("/comments/{}", id))); Some(links) } } impl Comment { fn add_author(comment: &mut ResourceObject, author: &ResourceObject) { let relationship = Relationship { data: OptionalVec::One(Some(author.try_into().unwrap())), ..Default::default() }; comment.add_relationship("author".into(), relationship); } } #[test] fn test() { let author = ResourceObject::new("9".into(), Some(People { first_name: "kitty".into(), last_name: "cat".into(), contact: "kitty@cat.space".into(), })); let person_2 = ResourceObject::::new("2".into(), None); let mut comment_5 = ResourceObject::new("5".into(), Some(Comment { body: "First!".into(), })); Comment::add_author(&mut comment_5, &person_2); let mut comment_12 = ResourceObject::new("12".into(), Some(Comment { body: "I like XML better".into(), })); Comment::add_author(&mut comment_12, &author); let comments = [comment_5, comment_12]; let mut article = ResourceObject::new("1".into(), Some(Article { title: "JSON:API is kind of strange in rust".into(), })); Article::add_author(&mut article, &author); Article::add_comments(&mut article, &comments); let mut included = Vec::new(); included.extend(comments.into_iter().map(|v| GenericObject::from(v))); included.push(author.into()); let document = Document { data: OptionalVec::One(Some(article.into())), included: Some(included), ..Default::default() }; let v1 = serde_json::to_value(&document).unwrap(); let v2 : serde_json::Value = serde_json::from_str(include_str!("article.json")).unwrap(); assert_eq!(v1, v2); }