use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
pub struct JsonApiResponse<T> {
pub data: T,
#[serde(default)]
pub links: Option<PagedDocumentLinks>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct PagedDocumentLinks {
#[serde(rename = "self")]
pub self_link: Option<String>,
pub next: Option<String>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Resource<A> {
pub id: String,
#[serde(rename = "type")]
pub resource_type: String,
pub attributes: A,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize_response_with_links() {
let json = r#"{
"data": {"id": "1", "type": "test", "attributes": {"name": "hello"}},
"links": {"self": "https://a.com/v1/test/1", "next": "https://a.com/v1/test?cursor=2"}
}"#;
#[derive(Debug, Deserialize, Serialize)]
struct Attrs {
name: String,
}
let resp: JsonApiResponse<Resource<Attrs>> = serde_json::from_str(json).unwrap();
assert_eq!(resp.data.id, "1");
assert_eq!(resp.data.attributes.name, "hello");
let links = resp.links.unwrap();
assert!(links.self_link.unwrap().contains("test/1"));
assert!(links.next.unwrap().contains("cursor=2"));
}
#[test]
fn test_deserialize_response_without_links() {
let json = r#"{"data": {"id": "2", "type": "x", "attributes": {}}}"#;
#[derive(Debug, Deserialize, Serialize)]
struct Empty {}
let resp: JsonApiResponse<Resource<Empty>> = serde_json::from_str(json).unwrap();
assert_eq!(resp.data.id, "2");
assert!(resp.links.is_none());
}
#[test]
fn test_deserialize_list_response() {
let json = r#"{"data": [
{"id": "1", "type": "t", "attributes": {"v": 10}},
{"id": "2", "type": "t", "attributes": {"v": 20}}
]}"#;
#[derive(Debug, Deserialize, Serialize)]
struct Val {
v: i32,
}
let resp: JsonApiResponse<Vec<Resource<Val>>> = serde_json::from_str(json).unwrap();
assert_eq!(resp.data.len(), 2);
assert_eq!(resp.data[0].attributes.v, 10);
assert_eq!(resp.data[1].attributes.v, 20);
}
}