1pub(crate) mod data;
2use crate::error::JsonApiError;
3use crate::link::Links;
4use crate::resource::ResourceType;
5use crate::{Link, ResourceTrait};
6pub use data::Data;
7pub use data::DataType;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Default, Clone, Deserialize, Serialize)]
11#[serde(rename_all = "camelCase")]
12pub struct JsonApi {
13 #[serde(skip_serializing_if = "Option::is_none")]
14 data: Option<Data>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 errors: Option<Vec<JsonApiError>>,
17 #[serde(borrow)]
19 jsonapi: JsonApiObject<'static>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 links: Option<Links>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 included: Option<Data>,
24}
25
26impl JsonApi {
27 pub fn new() -> Self {
28 JsonApi {
29 ..Default::default()
30 }
31 }
32
33 pub fn data(resource: impl ResourceTrait) -> Self {
34 JsonApi {
35 data: Some(Data::Singular(ResourceType::Object(
36 resource.to_resource_object(),
37 ))),
38 ..Default::default()
39 }
40 }
41
42 pub fn collection(resources: Vec<impl ResourceTrait>) -> Self {
43 JsonApi {
44 data: Some(Data::Array(
45 resources
46 .iter()
47 .map(|resource| ResourceType::Object(resource.to_resource_object()))
48 .collect(),
49 )),
50 ..Default::default()
51 }
52 }
53
54 pub fn error(error: JsonApiError) -> Self {
55 JsonApi {
56 errors: Some(vec![error]),
57 ..Default::default()
58 }
59 }
60
61 pub fn errors(errors: Vec<JsonApiError>) -> Self {
62 JsonApi {
63 errors: Some(errors),
64 ..Default::default()
65 }
66 }
67
68 pub fn links(&mut self, links: Vec<Link>) -> &mut Self {
69 self.links = Some(Links::new(links));
70 self
71 }
72
73 pub fn to_response(&self) -> Result<Self, Vec<ValidationError>> {
74 self.clone().validate()
75 }
76
77 fn validate(self) -> Result<Self, Vec<ValidationError>> {
78 let mut errors = vec![];
79 if self.data.is_none() && self.errors.is_none() {
80 errors.push(ValidationError::MissingTopLevelMembers);
81 }
82 if self.data.is_some() && self.errors.is_some() {
83 errors.push(ValidationError::DataErrorCoexist);
84 }
85 if self.data.is_none() && self.included.is_some() {
86 errors.push(ValidationError::MissingDataAndIncluded);
87 }
88 if errors.is_empty() {
89 Ok(self)
90 } else {
91 Err(errors)
92 }
93 }
94}
95
96#[derive(Debug)]
97pub enum ValidationError {
98 MissingTopLevelMembers,
99 DataErrorCoexist,
100 MissingDataAndIncluded,
101}
102
103#[derive(Debug, Clone, Deserialize, Serialize)]
104struct JsonApiObject<'a> {
105 version: &'a str,
106 }
108
109impl Default for JsonApiObject<'_> {
110 fn default() -> Self {
111 JSON_API_OBJECT
112 }
113}
114
115const JSON_API_OBJECT: JsonApiObject<'static> = { JsonApiObject { version: "1.0" } };