1use std::borrow::Cow;
2use std::marker::PhantomData;
3
4use serde::{Serialize, Serializer};
5
6type StrCow = Cow<'static, str>;
7
8const DEFAULT_SUCCESS_CODE: &str = "0";
9const DEFAULT_ERROR_CODE: &str = "-1";
10const DEFAULT_ERROR_MESSAGE: &str = "Internal server error";
11
12#[derive(Default)]
13pub struct ApiJsonErrorBuilder<T> {
14 code: Option<StrCow>,
15 error: Option<StrCow>,
16 _phantom: PhantomData<T>,
17}
18
19impl<T: Serialize> ApiJsonErrorBuilder<T> {
20 pub fn new() -> Self {
21 Self {
22 code: None,
23 error: None,
24 _phantom: PhantomData,
25 }
26 }
27
28 pub fn code(mut self, code: impl Into<StrCow>) -> Self {
29 self.code = Some(code.into());
30 self
31 }
32
33 pub fn error(mut self, error: impl Into<StrCow>) -> Self {
34 self.error = Some(error.into());
35 self
36 }
37
38 pub fn build(self) -> ApiJson<T> {
39 ApiJson::Error {
40 code: self.code.or_else(|| Some(DEFAULT_ERROR_CODE.into())),
41 error: self.error.or_else(|| Some(DEFAULT_ERROR_MESSAGE.into())),
42 }
43 }
44}
45
46pub enum ApiJson<T> {
48 Data {
49 code: Option<StrCow>,
50 data: Option<T>,
51 },
52 Error {
53 code: Option<StrCow>,
54 error: Option<StrCow>,
55 },
56}
57
58impl<T: Serialize> ApiJson<T> {
59 pub fn ok(data: T) -> Self {
60 Self::Data {
61 data: Some(data),
62 code: None,
63 }
64 }
65
66 pub fn data_with_code(data: T, code: StrCow) -> Self {
67 Self::Data {
68 data: Some(data),
69 code: Some(code),
70 }
71 }
72
73 pub fn error_builder() -> ApiJsonErrorBuilder<T> {
74 ApiJsonErrorBuilder::<T>::new()
75 }
76
77 fn as_serializable(&self) -> ApiJsonSerializable<'_, T> {
78 match *self {
79 Self::Data { ref code, ref data } => ApiJsonSerializable {
80 code: code.as_deref().unwrap_or(DEFAULT_SUCCESS_CODE),
81 error: None,
82 data: data.as_ref(),
83 },
84 Self::Error {
85 ref code,
86 ref error,
87 } => ApiJsonSerializable {
88 code: code.as_deref().unwrap_or(DEFAULT_ERROR_CODE),
89 error: error.as_deref(),
90 data: None,
91 },
92 }
93 }
94}
95
96impl ApiJson<()> {
97 pub fn unit_error_builder() -> ApiJsonErrorBuilder<()> {
99 ApiJsonErrorBuilder::new()
100 }
101
102 pub fn no_content() -> Self {
103 Self::Data {
104 data: Some(()),
105 code: None,
106 }
107 }
108
109 pub const fn default_error() -> Self {
110 Self::Error {
111 code: Some(StrCow::Borrowed(DEFAULT_ERROR_CODE)),
112 error: Some(StrCow::Borrowed(DEFAULT_ERROR_MESSAGE)),
113 }
114 }
115}
116
117impl<T: Serialize> Serialize for ApiJson<T> {
118 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
119 where
120 S: Serializer,
121 {
122 Serialize::serialize(&self.as_serializable(), serializer)
123 }
124}
125
126#[derive(Serialize)]
127struct ApiJsonSerializable<'a, T> {
128 code: &'a str,
129 #[serde(rename = "data", skip_serializing_if = "Option::is_none")]
130 data: Option<&'a T>,
131 #[serde(rename = "message", skip_serializing_if = "Option::is_none")]
132 error: Option<&'a str>,
133}
134
135#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
136pub enum JsonMode {
137 Normal,
138 Pretty,
139}
140
141impl JsonMode {
142 pub fn to_string<T>(self, value: &T) -> serde_json::Result<String>
143 where
144 T: ?Sized + Serialize,
145 {
146 match self {
147 Self::Normal => serde_json::to_string(value),
148 Self::Pretty => serde_json::to_string_pretty(value),
149 }
150 }
151
152 pub fn to_vec<T>(self, value: &T) -> serde_json::Result<Vec<u8>>
153 where
154 T: ?Sized + Serialize,
155 {
156 match self {
157 Self::Normal => serde_json::to_vec(value),
158 Self::Pretty => serde_json::to_vec_pretty(value),
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use serde_json::json;
166
167 use super::*;
168
169 #[derive(Serialize, Clone)]
170 struct TestData {
171 foo: String,
172 }
173
174 #[test]
175 fn test_ok_data() {
176 let data = TestData {
177 foo: "bar".to_owned(),
178 };
179
180 let json = ApiJson::ok(data);
181 let actual = serde_json::to_value(json).unwrap();
182
183 let expect = json!({
184 "code": DEFAULT_SUCCESS_CODE,
185 "data": {
186 "foo": "bar"
187 },
188 });
189
190 assert_eq!(actual, expect);
191 }
192
193 #[test]
194 fn test_ok_data_with_code() {
195 let data = TestData {
196 foo: "bar".to_owned(),
197 };
198
199 let json = ApiJson::data_with_code(data, "Nani!".into());
200 let actual = serde_json::to_value(json).unwrap();
201
202 let expect = json!({
203 "code": "Nani!",
204 "data": {
205 "foo": "bar"
206 },
207 });
208
209 assert_eq!(actual, expect);
210 }
211
212 #[test]
213 fn test_no_content() {
214 let json = ApiJson::no_content();
215 let actual = serde_json::to_value(json).unwrap();
216
217 let expect = json!({
218 "code": DEFAULT_SUCCESS_CODE,
219 "data": serde_json::Value::Null,
220 });
221
222 assert_eq!(actual, expect);
223 }
224
225 #[test]
226 fn test_build_default_error_message() {
227 let json = ApiJson::unit_error_builder().build();
228 let actual = serde_json::to_value(json).unwrap();
229 let expect = json!({
230 "code": DEFAULT_ERROR_CODE,
231 "message": DEFAULT_ERROR_MESSAGE,
232 });
233 assert_eq!(actual, expect);
234 }
235
236 #[test]
237 fn test_build_error_with_message() {
238 let json = ApiJson::unit_error_builder().error("foo").build();
239 let actual = serde_json::to_value(json).unwrap();
240 let expect = json!({
241 "code": DEFAULT_ERROR_CODE,
242 "message": "foo",
243 });
244 assert_eq!(actual, expect);
245 }
246
247 #[test]
248 fn test_build_error_with_code_and_message() {
249 let json = ApiJson::unit_error_builder()
250 .code("-1")
251 .error("bar")
252 .build();
253 let actual = serde_json::to_value(json).unwrap();
254 let expect = json!({
255 "code": "-1",
256 "message": "bar",
257 });
258 assert_eq!(actual, expect);
259 }
260
261 #[test]
262 fn test_api_json_is_send_and_sync() {
263 fn require_send(_: impl Send + Sync) {}
264 require_send(ApiJson::ok(()));
265 }
266}