use axum::{
Json,
http::StatusCode,
response::{IntoResponse, Response},
};
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct SuccessBody<T: Serialize> {
pub status: u16,
pub data: T,
}
#[derive(Debug, Serialize)]
pub struct ErrorBody {
pub status: u16,
pub error: String,
}
pub enum ApiResponse<T: Serialize> {
Success(StatusCode, T),
Error(StatusCode, String),
}
impl<T: Serialize> ApiResponse<T> {
pub fn ok(data: T) -> Self {
Self::Success(StatusCode::OK, data)
}
pub fn created(data: T) -> Self {
Self::Success(StatusCode::CREATED, data)
}
pub fn success(status: StatusCode, data: T) -> Self {
Self::Success(status, data)
}
pub fn error(status: StatusCode, message: impl Into<String>) -> Self {
Self::Error(status, message.into())
}
pub fn bad_request(message: impl Into<String>) -> Self {
Self::error(StatusCode::BAD_REQUEST, message)
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::error(StatusCode::NOT_FOUND, message)
}
pub fn unauthorized(message: impl Into<String>) -> Self {
Self::error(StatusCode::UNAUTHORIZED, message)
}
pub fn forbidden(message: impl Into<String>) -> Self {
Self::error(StatusCode::FORBIDDEN, message)
}
pub fn internal_error(message: impl Into<String>) -> Self {
Self::error(StatusCode::INTERNAL_SERVER_ERROR, message)
}
}
impl<T: Serialize> IntoResponse for ApiResponse<T> {
fn into_response(self) -> Response {
match self {
ApiResponse::Success(status, data) => {
let body = SuccessBody {
status: status.as_u16(),
data,
};
(status, Json(body)).into_response()
}
ApiResponse::Error(status, message) => {
let body = ErrorBody {
status: status.as_u16(),
error: message,
};
(status, Json(body)).into_response()
}
}
}
}