Skip to main content

imgurs_model/model/
basic.rs

1//! API response specification
2use serde::{Deserialize, Serialize};
3
4use crate::error::ErrorMessage;
5
6/// API response common fields
7///
8/// This is the basic response for requests that do not return data. If the POST request has a Basic model it will return the id.
9#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11#[serde(deny_unknown_fields)]
12pub struct Basic<T> {
13    /// Response data
14    pub data: Data<T>,
15    /// Success status
16    pub success: bool,
17    /// HTTP status
18    pub status: u16,
19}
20
21impl<T> From<Basic<T>> for Result<T, ErrorMessage> {
22    fn from(b: Basic<T>) -> Self {
23        b.data.into()
24    }
25}
26
27impl<T> Basic<T> {
28    /// Convert Basic into a result
29    pub fn result(self) -> Result<T, ErrorMessage> {
30        self.into()
31    }
32}
33
34/// API response data
35#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37#[serde(deny_unknown_fields)]
38#[serde(untagged)]
39pub enum Data<T> {
40    /// Content in the response
41    Content(T),
42    /// Error in the response
43    Error {
44        /// Error message
45        error: ErrorMessage,
46        /// Requested content
47        request: String,
48        /// Method used in the request
49        method: Method,
50    },
51}
52
53impl<T> From<Data<T>> for Result<T, ErrorMessage> {
54    fn from(d: Data<T>) -> Self {
55        match d {
56            Data::Content(c) => Ok(c),
57            Data::Error {
58                error,
59                request: _,
60                method: _,
61            } => Err(error),
62        }
63    }
64}
65
66/// HTTP methods
67#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
68#[serde(rename_all = "UPPERCASE")]
69#[serde(deny_unknown_fields)]
70pub enum Method {
71    /// Get method
72    GET,
73    /// Post method
74    POST,
75    /// Put method
76    PUT,
77    /// Delete method
78    DELETE,
79}
80
81#[cfg(test)]
82mod test {
83    use std::error::Error;
84
85    use crate::model::{
86        account_settings::AccountSettings,
87        basic::{Basic, Data, ErrorMessage, Method},
88    };
89
90    #[test]
91    fn test_error_parsing_local() -> Result<(), Box<dyn Error>> {
92        let res = r#"{
93            "data": {
94                "error": "Authentication required",
95                "request": "/3/account/me/settings",
96                "method": "GET"
97            },
98            "success": false,
99            "status": 401
100        }"#;
101
102        let data = serde_json::from_str::<Basic<AccountSettings>>(res)?;
103        assert!(!data.success);
104        assert_eq!(data.status, 401);
105        match data.data {
106            Data::Content(_) => panic!("Should return error"),
107            Data::Error {
108                error,
109                request,
110                method,
111            } => {
112                assert_eq!(error, ErrorMessage::new("Authentication required"));
113                assert_eq!(request, "/3/account/me/settings");
114                assert_eq!(method, Method::GET);
115            }
116        }
117
118        Ok(())
119    }
120}