json_resp/
response.rs

1use std::fmt;
2
3use axum::{
4    http::StatusCode,
5    response::{IntoResponse, Response},
6    Json,
7};
8use serde::Serialize;
9
10fn as_u16<S>(status: &StatusCode, serializer: S) -> Result<S::Ok, S::Error>
11where
12    S: serde::Serializer,
13{
14    serializer.serialize_u16(status.as_u16())
15}
16
17#[derive(Debug, Default, Serialize)]
18pub struct Nothing;
19
20#[derive(Debug, Default, Serialize)]
21pub struct JsonListMeta {
22    #[serde(skip_serializing_if = "Option::is_none")]
23    total: Option<usize>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    next: Option<String>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    prev: Option<String>,
28}
29
30impl JsonListMeta {
31    pub fn next(mut self, next: String) -> Self {
32        self.next = Some(next);
33        self
34    }
35
36    pub fn prev(mut self, prev: String) -> Self {
37        self.prev = Some(prev);
38        self
39    }
40
41    pub fn total(mut self, total: usize) -> Self {
42        self.total = Some(total);
43        self
44    }
45}
46
47#[derive(Debug, Serialize)]
48pub struct JsonResponse<T = Nothing, M = Nothing> {
49    #[serde(serialize_with = "as_u16")]
50    pub status: StatusCode,
51    pub content: T,
52    pub meta: M,
53}
54
55impl<T, M> Default for JsonResponse<T, M>
56where
57    T: Default,
58    M: Default,
59{
60    fn default() -> Self {
61        Self {
62            status: StatusCode::OK,
63            content: T::default(),
64            meta: M::default(),
65        }
66    }
67}
68
69impl JsonResponse {
70    pub fn new() -> Self {
71        Self::default()
72    }
73}
74
75impl<T> JsonResponse<T> {
76    pub fn with_content(content: T) -> Self {
77        Self {
78            status: StatusCode::OK,
79            content,
80            meta: Nothing,
81        }
82    }
83}
84
85impl<T, M> JsonResponse<T, M> {
86    pub fn content<T2>(self, content: T2) -> JsonResponse<T2, M> {
87        JsonResponse {
88            status: self.status,
89            content,
90            meta: self.meta,
91        }
92    }
93
94    pub fn meta<M2>(self, meta: M2) -> JsonResponse<T, M2> {
95        JsonResponse {
96            status: self.status,
97            content: self.content,
98            meta,
99        }
100    }
101}
102
103impl<T, M> fmt::Display for JsonResponse<T, M>
104where
105    T: Serialize,
106    M: Serialize,
107{
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        f.write_str("JsonResponse: ")?;
110        f.write_str(&serde_json::to_string_pretty(self).map_err(|_err| fmt::Error)?)
111    }
112}
113
114impl<T, M> IntoResponse for JsonResponse<T, M>
115where
116    T: Serialize,
117    M: Serialize,
118{
119    fn into_response(self) -> Response {
120        (self.status, Json(&self)).into_response()
121    }
122}
123
124/////////////////////////////////////////////////////////////////////////////////////////
125
126#[derive(Default, Debug, Serialize)]
127pub struct JsonError<T = Nothing> {
128    #[serde(serialize_with = "as_u16")]
129    pub status: StatusCode,
130    pub code: &'static str,
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub hint: Option<String>,
133    pub content: T,
134}
135
136impl JsonError {
137    pub fn new(status: StatusCode, code: &'static str) -> Self {
138        Self {
139            status,
140            code,
141            ..Default::default()
142        }
143    }
144}
145
146impl<T> JsonError<T> {
147    pub fn with_content(status: StatusCode, code: &'static str, content: T) -> Self {
148        Self {
149            status,
150            code,
151            hint: None,
152            content,
153        }
154    }
155
156    pub fn hint(mut self, hint: String) -> Self {
157        self.hint = Some(hint);
158        self
159    }
160
161    pub fn content<B>(self, content: B) -> JsonError<B> {
162        JsonError {
163            status: self.status,
164            code: self.code,
165            hint: self.hint,
166            content,
167        }
168    }
169}
170
171impl<T> fmt::Display for JsonError<T> {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        f.write_str("JsonError: ")?;
174        f.write_str(self.code)
175    }
176}
177
178impl<T> IntoResponse for JsonError<T>
179where
180    T: Serialize + 'static,
181{
182    fn into_response(self) -> axum::response::Response {
183        (self.status, Json(&self)).into_response()
184    }
185}