use axum::{ Json, http::StatusCode, response::{IntoResponse, Response}, }; use serde::Serialize; /// Generic response structure shared by all API responses. #[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct ResponseBody { #[serde(rename = "status")] status_code: u16, data: T, } impl ResponseBody { pub fn new(status: StatusCode, data: T) -> Self { Self { status_code: status.as_u16(), data, } } } #[derive(Debug, Clone)] pub struct ApiSuccess(StatusCode, Json>); impl PartialEq for ApiSuccess where T: Serialize + PartialEq, { fn eq(&self, other: &Self) -> bool { self.0 == other.0 && self.1.0 == other.1.0 } } impl ApiSuccess { pub fn new(status: StatusCode, data: T) -> Self { Self(status, Json(ResponseBody::new(status, data))) } } impl IntoResponse for ApiSuccess { fn into_response(self) -> Response { (self.0, self.1).into_response() } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum ApiError { BadRequest(String), NotFound(String), InternalServerError(String), } impl From for ApiError { fn from(e: anyhow::Error) -> Self { Self::InternalServerError(e.to_string()) } } impl IntoResponse for ApiError { fn into_response(self) -> Response { use ApiError::*; match self { BadRequest(e) => (StatusCode::BAD_REQUEST, e).into_response(), NotFound(e) => (StatusCode::NOT_FOUND, e).into_response(), InternalServerError(e) => { tracing::error!("{}", e); ( StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error".to_string(), ) .into_response() } } } }