utoipa_helper/
json_response.rs

1use axum::Json;
2use axum::http::header::HeaderValue;
3use axum::http::header::SET_COOKIE;
4use axum::response::IntoResponse;
5use serde::Serialize;
6use std::convert::TryFrom;
7use utoipa::PartialSchema;
8use utoipa::ToSchema;
9
10pub struct JsonResponse<T>
11where
12    T: ToSchema + Serialize + Send,
13{
14    data: T,
15    cookies: Option<Vec<String>>,
16}
17
18impl<T> JsonResponse<T>
19where
20    T: ToSchema + Serialize + Send,
21{
22    pub fn new(data: T) -> Self {
23        Self {
24            data,
25            cookies: None,
26        }
27    }
28
29    #[must_use]
30    pub fn with_cookie(mut self, cookie: impl Into<String>) -> Self {
31        if let Some(cookies) = self.cookies.as_mut() {
32            cookies.push(cookie.into());
33        } else {
34            self.cookies = Some(vec![cookie.into()]);
35        }
36        self
37    }
38}
39
40impl<T> IntoResponse for JsonResponse<T>
41where
42    T: ToSchema + Serialize + Send,
43{
44    fn into_response(self) -> axum::response::Response {
45        let mut res = Json(self.data).into_response();
46        if let Some(cookies) = self.cookies {
47            for cookie in cookies {
48                if let Ok(value) = <HeaderValue as TryFrom<String>>::try_from(cookie) {
49                    res.headers_mut().append(SET_COOKIE, value);
50                }
51            }
52        }
53        res
54    }
55}
56
57impl<T> PartialSchema for JsonResponse<T>
58where
59    T: ToSchema + Serialize + Send,
60{
61    fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
62        T::schema()
63    }
64}
65
66impl<T> ToSchema for JsonResponse<T>
67where
68    T: ToSchema + Serialize + Send,
69{
70    fn name() -> std::borrow::Cow<'static, str> {
71        T::name()
72    }
73
74    fn schemas(
75        schemas: &mut Vec<(
76            String,
77            utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
78        )>,
79    ) {
80        T::schemas(schemas);
81    }
82}