fundamentum_edge_mcu_http_client/models/api_response/
mod.rs1use failed_data::ApiResponseFailedData;
2use failed_empty::ApiResponseFailedEmpty;
3use serde::Deserialize;
4
5pub mod failed_data;
6pub mod failed_empty;
7
8#[derive(Deserialize)]
10#[cfg_attr(feature = "log", derive(defmt::Format))]
11#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
12#[serde(rename_all = "lowercase")]
13pub enum ApiStatus {
14 Success,
16 Error,
18}
19
20#[derive(Deserialize)]
22#[cfg_attr(feature = "log", derive(defmt::Format))]
23#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
24#[serde(bound(deserialize = "T: Deserialize<'de>"))]
25pub struct ApiResponse<'a, T> {
26 #[serde(rename = "status")]
28 pub status: Option<ApiStatus>,
29 #[serde(rename = "message")]
31 pub message: Option<&'a str>,
32 #[serde(rename = "data")]
37 pub data: Option<T>,
38}
39
40impl<'a, T: Deserialize<'a>> From<ApiResponseFailedData<'a>> for ApiResponse<'a, T> {
41 fn from(response: ApiResponseFailedData<'a>) -> Self {
42 ApiResponse {
43 status: response.status,
44 message: response.message,
45 data: None,
46 }
47 }
48}
49
50impl<'a, T: Deserialize<'a>> From<ApiResponseFailedEmpty<'a>> for ApiResponse<'a, T> {
51 fn from(response: ApiResponseFailedEmpty<'a>) -> Self {
52 ApiResponse {
53 status: response.status,
54 message: response.message,
55 data: None,
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62
63 use failed_data::{ApiError, ApiErrors, MAX_NUMBER_OF_ERRORS};
64 use failed_empty::Empty;
65 use indoc::indoc;
66
67 use crate::models::provision_response::{MqttBroker, ProvisionResponse};
68
69 use super::*;
70
71 #[test]
72 fn given_successful_body_when_deserializing_api_response_then_successfully_deserialize() {
73 let body = indoc! {r#"
74 {
75 "status": "success",
76 "data": {
77 "configuration": null,
78 "mqtt": {
79 "host": "mqtts.fundamentum-iot-dev.com",
80 "port": 8883
81 }
82 }
83 }"#};
84
85 let (api_response, _size): (ApiResponse<ProvisionResponse<Empty>>, usize) =
86 serde_json_core::from_slice(body.as_bytes()).unwrap();
87
88 let expected_response = ApiResponse {
89 status: Some(ApiStatus::Success),
90 message: None,
91 data: Some(ProvisionResponse {
92 configuration: None,
93 mqtt: MqttBroker {
94 host: "mqtts.fundamentum-iot-dev.com",
95 port: 8883,
96 },
97 }),
98 };
99
100 assert_eq!(api_response, expected_response);
101 }
102
103 #[test]
104 fn given_failed_body_with_errors_when_deserializing_api_response_failed_data_then_successfully_deserialize(
105 ) {
106 let body = indoc! {r#"
107 {
108 "status": "error",
109 "message": "There is an error with the request's content",
110 "data": {
111 "errors": [
112 {
113 "type": "field",
114 "value": "serial_number_1S",
115 "msg": "Invalid value",
116 "path": "serial_number",
117 "location": "body"
118 }
119 ]
120 }
121 }"#};
122
123 let (api_response, _size): (ApiResponseFailedData, usize) =
124 serde_json_core::from_slice(body.as_bytes()).unwrap();
125
126 let mut array = [None; MAX_NUMBER_OF_ERRORS];
127 array[0] = Some(ApiError {
128 r#type: "field",
129 value: "serial_number_1S",
130 msg: "Invalid value",
131 path: "serial_number",
132 location: "body",
133 });
134 let expected_response = ApiResponseFailedData {
135 status: Some(ApiStatus::Error),
136 message: Some("There is an error with the request's content"),
137 data: Some(ApiErrors {
138 errors: Some(array),
139 }),
140 };
141
142 assert_eq!(api_response, expected_response);
143 }
144
145 #[test]
146 fn given_failed_body_with_no_errors_when_deserializing_api_response_failed_empty_then_successfully_deserialize(
147 ) {
148 let body = indoc! {r#"
149 {
150 "status": "error",
151 "message": "No Registry to provision device on this project",
152 "data": {}
153 }"#};
154
155 let (api_response, _size): (ApiResponseFailedEmpty, usize) =
156 serde_json_core::from_slice(body.as_bytes()).unwrap();
157
158 let expected_response = ApiResponseFailedEmpty {
159 status: Some(ApiStatus::Error),
160 message: Some("No Registry to provision device on this project"),
161 data: Some(Empty {}),
162 };
163
164 assert_eq!(api_response, expected_response);
165 }
166}