use axum::Json; use axum::extract::{FromRequest, Request}; use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::fmt; use std::ops::{Deref, DerefMut}; use utoipa::ToSchema; #[derive(Debug, Serialize, Deserialize, ToSchema)] pub struct NoData; #[derive(Serialize, Deserialize, Debug, ToSchema)] pub struct AppResponseData { pub code: i32, pub message: String, pub data: Option, pub error: Option, pub duration: String, pub request_id: String, pub at: String, pub log_id: String, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct AppRequestData { pub request_id: String, pub at: String, pub data: Option, } impl AppResponseData where T: Serialize, { pub fn ok(data: T) -> Self { AppResponseData { code: 200, message: "success".to_string(), data: Some(data), error: None, duration: String::new(), request_id: String::new(), at: String::new(), log_id: String::new(), } } pub fn err(code: i32, message: impl Into) -> Self { AppResponseData { code, message: message.into(), data: None, error: None, duration: String::new(), request_id: String::new(), at: String::new(), log_id: String::new(), } } pub fn err_with_detail( code: i32, message: impl Into, detail: impl Into, ) -> Self { AppResponseData { code, message: message.into(), data: None, error: Some(detail.into()), duration: String::new(), request_id: String::new(), at: String::new(), log_id: String::new(), } } pub fn with_code(mut self, code: i32) -> Self { self.code = code; self } pub fn with_message(mut self, message: impl Into) -> Self { self.message = message.into(); self } pub fn with_error(mut self, error: impl Into) -> Self { self.error = Some(error.into()); self } pub fn with_duration(mut self, duration: impl Into) -> Self { self.duration = duration.into(); self } pub fn with_request_id(mut self, request_id: impl Into) -> Self { self.request_id = request_id.into(); self } pub fn with_at(mut self, at: impl Into) -> Self { self.at = at.into(); self } pub fn with_log_id(mut self, log_id: impl Into) -> Self { self.log_id = log_id.into(); self } } impl AppResponseData { pub fn empty() -> Self { AppResponseData { code: 200, message: "success".to_string(), data: None, error: None, duration: String::new(), request_id: String::new(), at: String::new(), log_id: String::new(), } } pub fn err_plain(code: i32, message: impl Into) -> Self { let msg = message.into(); AppResponseData { code, message: msg.clone(), data: None, error: Some(msg), duration: String::new(), request_id: String::new(), at: String::new(), log_id: String::new(), } } } impl fmt::Display for AppResponseData<()> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "API error: code={}, message={}", self.code, self.message) } } impl IntoResponse for AppResponseData { fn into_response(self) -> Response { let status = StatusCode::from_u16(self.code as u16).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR); (status, Json(self)).into_response() } } #[derive(Debug)] pub struct AppRequest(pub T); impl AppRequest { pub fn into_inner(self) -> T { self.0 } } impl Deref for AppRequest { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for AppRequest { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl FromRequest for AppRequest where T: DeserializeOwned + 'static, S: Send + Sync, { type Rejection = AppResponseData<()>; async fn from_request(req: Request, state: &S) -> Result { let Json(payload) = Json::>::from_request(req, state) .await .map_err(|e| AppResponseData::<()>::err(400, format!("invalid request body: {}", e)))?; match payload.data { Some(data) => Ok(AppRequest(data)), None => Err(AppResponseData::<()>::err(400, "missing request data")), } } }