sylvia_iot_corelib/
http.rs1use axum::{
2 extract::{
3 rejection::JsonRejection, FromRequest, FromRequestParts, Json as AxumJson,
4 Path as AxumPath, Query as AxumQuery, Request,
5 },
6 http::{header, request::Parts},
7 response::{IntoResponse, Response},
8};
9use bytes::{BufMut, BytesMut};
10use serde::{de::DeserializeOwned, Serialize};
11
12use crate::{constants::ContentType, err::ErrResp};
13
14pub struct Json<T>(pub T);
18
19pub struct Path<T>(pub T);
23
24pub struct Query<T>(pub T);
28
29impl<S, T> FromRequest<S> for Json<T>
30where
31 AxumJson<T>: FromRequest<S, Rejection = JsonRejection>,
32 S: Send + Sync,
33{
34 type Rejection = ErrResp;
35
36 async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
37 match AxumJson::<T>::from_request(req, state).await {
38 Err(e) => Err(ErrResp::ErrParam(Some(e.to_string()))),
39 Ok(value) => Ok(Self(value.0)),
40 }
41 }
42}
43
44impl<T> IntoResponse for Json<T>
45where
46 T: Serialize,
47{
48 fn into_response(self) -> Response {
49 let mut buf = BytesMut::with_capacity(128).writer();
52 match serde_json::to_writer(&mut buf, &self.0) {
53 Err(e) => ErrResp::ErrUnknown(Some(e.to_string())).into_response(),
54 Ok(()) => (
55 [(header::CONTENT_TYPE, ContentType::JSON)],
56 buf.into_inner().freeze(),
57 )
58 .into_response(),
59 }
60 }
61}
62
63impl<T, S> FromRequestParts<S> for Path<T>
64where
65 T: DeserializeOwned + Send,
66 S: Send + Sync,
67{
68 type Rejection = ErrResp;
69
70 async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
71 match AxumPath::from_request_parts(parts, state).await {
72 Err(e) => Err(ErrResp::ErrParam(Some(e.to_string()))),
73 Ok(value) => Ok(Self(value.0)),
74 }
75 }
76}
77
78impl<T, S> FromRequestParts<S> for Query<T>
79where
80 T: DeserializeOwned,
81 S: Send + Sync,
82{
83 type Rejection = ErrResp;
84
85 async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
86 match AxumQuery::from_request_parts(parts, state).await {
87 Err(e) => Err(ErrResp::ErrParam(Some(e.to_string()))),
88 Ok(value) => Ok(Self(value.0)),
89 }
90 }
91}
92
93pub fn parse_header_auth(req: &Request) -> Result<Option<String>, ErrResp> {
95 let mut auth_all = req.headers().get_all(header::AUTHORIZATION).iter();
96 let auth = match auth_all.next() {
97 None => return Ok(None),
98 Some(auth) => match auth.to_str() {
99 Err(e) => return Err(ErrResp::ErrParam(Some(e.to_string()))),
100 Ok(auth) => auth,
101 },
102 };
103 if auth_all.next() != None {
104 return Err(ErrResp::ErrParam(Some(
105 "invalid multiple Authorization header".to_string(),
106 )));
107 }
108 Ok(Some(auth.to_string()))
109}