sylvia_iot_corelib/
http.rsuse async_trait::async_trait;
use axum::{
extract::{
rejection::JsonRejection, FromRequest, FromRequestParts, Json as AxumJson,
Path as AxumPath, Query as AxumQuery, Request,
},
http::{header, request::Parts},
response::{IntoResponse, Response},
};
use bytes::{BufMut, BytesMut};
use serde::{de::DeserializeOwned, Serialize};
use crate::{constants::ContentType, err::ErrResp};
pub struct Json<T>(pub T);
pub struct Path<T>(pub T);
pub struct Query<T>(pub T);
#[async_trait]
impl<S, T> FromRequest<S> for Json<T>
where
AxumJson<T>: FromRequest<S, Rejection = JsonRejection>,
S: Send + Sync,
{
type Rejection = ErrResp;
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
match AxumJson::<T>::from_request(req, state).await {
Err(e) => Err(ErrResp::ErrParam(Some(e.to_string()))),
Ok(value) => Ok(Self(value.0)),
}
}
}
impl<T> IntoResponse for Json<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
let mut buf = BytesMut::with_capacity(128).writer();
match serde_json::to_writer(&mut buf, &self.0) {
Err(e) => ErrResp::ErrUnknown(Some(e.to_string())).into_response(),
Ok(()) => (
[(header::CONTENT_TYPE, ContentType::JSON)],
buf.into_inner().freeze(),
)
.into_response(),
}
}
}
#[async_trait]
impl<T, S> FromRequestParts<S> for Path<T>
where
T: DeserializeOwned + Send,
S: Send + Sync,
{
type Rejection = ErrResp;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match AxumPath::from_request_parts(parts, state).await {
Err(e) => Err(ErrResp::ErrParam(Some(e.to_string()))),
Ok(value) => Ok(Self(value.0)),
}
}
}
#[async_trait]
impl<T, S> FromRequestParts<S> for Query<T>
where
T: DeserializeOwned,
S: Send + Sync,
{
type Rejection = ErrResp;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match AxumQuery::from_request_parts(parts, state).await {
Err(e) => Err(ErrResp::ErrParam(Some(e.to_string()))),
Ok(value) => Ok(Self(value.0)),
}
}
}
pub fn parse_header_auth(req: &Request) -> Result<Option<String>, ErrResp> {
let mut auth_all = req.headers().get_all(header::AUTHORIZATION).iter();
let auth = match auth_all.next() {
None => return Ok(None),
Some(auth) => match auth.to_str() {
Err(e) => return Err(ErrResp::ErrParam(Some(e.to_string()))),
Ok(auth) => auth,
},
};
if auth_all.next() != None {
return Err(ErrResp::ErrParam(Some(
"invalid multiple Authorization header".to_string(),
)));
}
Ok(Some(auth.to_string()))
}