j_api/json_api/
mod.rs

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    // TODO: Meta
18    #[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    // TODO: Meta
107}
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" } };