gitdataai/libs/api/error.rs
2026-04-15 09:08:09 +08:00

114 lines
3.0 KiB
Rust

use actix_web::{HttpResponse, ResponseError};
use serde::Serialize;
use service::error::AppError;
use utoipa::openapi::schema::{KnownFormat, ObjectBuilder, SchemaFormat, Type};
use utoipa::openapi::{RefOr, Schema};
use utoipa::{PartialSchema, ToSchema};
#[derive(Debug, Serialize, ToSchema)]
pub struct ApiResponse<T> {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<T>,
}
impl<T: Serialize> ApiResponse<T> {
pub fn ok(data: T) -> Self {
Self {
code: 0,
message: "ok".to_string(),
data: Some(data),
}
}
pub fn to_response(self) -> HttpResponse {
HttpResponse::Ok().json(self)
}
}
pub fn api_success() -> HttpResponse {
HttpResponse::Ok().json(ApiResponse {
code: 0,
message: "ok".to_string(),
data: None::<()>,
})
}
#[derive(Debug, Serialize, ToSchema)]
pub struct ApiErrorResponse {
pub code: i32,
pub error: String,
pub message: String,
}
#[derive(Debug)]
pub struct ApiError(pub AppError);
impl std::fmt::Display for ApiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.user_message().fmt(f)
}
}
impl std::error::Error for ApiError {}
impl From<AppError> for ApiError {
fn from(e: AppError) -> Self {
ApiError(e)
}
}
impl From<room::RoomError> for ApiError {
fn from(e: room::RoomError) -> Self {
ApiError(e.into())
}
}
impl ResponseError for ApiError {
fn error_response(&self) -> HttpResponse {
let err = &self.0;
let status = actix_web::http::StatusCode::from_u16(err.http_status_code())
.unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR);
let resp = ApiErrorResponse {
code: err.code(),
error: err.slug().to_string(),
message: err.user_message(),
};
HttpResponse::build(status).json(resp)
}
}
impl PartialSchema for ApiError {
fn schema() -> RefOr<Schema> {
RefOr::T(Schema::Object(
ObjectBuilder::new()
.property(
"code",
ObjectBuilder::new()
.schema_type(Type::Integer)
.format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
.description(Some("Error numeric code")),
)
.property(
"error",
ObjectBuilder::new()
.schema_type(Type::String)
.description(Some("Error slug identifier")),
)
.property(
"message",
ObjectBuilder::new()
.schema_type(Type::String)
.description(Some("Human-readable error message")),
)
.required("code")
.required("error")
.required("message")
.into(),
))
}
}
impl ToSchema for ApiError {}