plc_control/src/util/response.rs

145 lines
4.1 KiB
Rust

use anyhow::Error;
use axum::{
Json,
http::StatusCode,
response::IntoResponse,
extract::rejection::{
QueryRejection,
PathRejection,
JsonRejection,
FormRejection,
},
};
use serde::Serialize;
use serde_json::Value;
use sqlx::Error as SqlxError;
#[derive(Debug, Serialize)]
pub struct ErrResp {
pub err_code: i32,
pub err_msg: String,
pub err_detail: Option<Value>,
}
impl ErrResp {
pub fn new(err_code: i32, err_msg: impl Into<String>, detail: Option<Value>) -> Self {
Self {
err_code,
err_msg: err_msg.into(),
err_detail: detail,
}
}
}
#[derive(Debug)]
#[allow(dead_code)]
pub enum ApiErr {
Unauthorized(String, Option<Value>),
Forbidden(String, Option<Value>),
BadRequest(String, Option<Value>),
NotFound(String, Option<Value>),
Internal(String, Option<Value>),
}
impl IntoResponse for ApiErr {
fn into_response(self) -> axum::response::Response {
match self {
ApiErr::Unauthorized(msg, detail) => {
(StatusCode::UNAUTHORIZED, Json(ErrResp::new(401, msg, detail))).into_response()
}
ApiErr::Forbidden(msg, detail) => {
(StatusCode::FORBIDDEN, Json(ErrResp::new(403, msg, detail))).into_response()
}
ApiErr::BadRequest(msg, detail) => {
(StatusCode::BAD_REQUEST, Json(ErrResp::new(400, msg, detail))).into_response()
}
ApiErr::NotFound(msg, detail) => {
(StatusCode::NOT_FOUND, Json(ErrResp::new(404, msg, detail))).into_response()
}
ApiErr::Internal(msg, detail) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrResp::new(500, msg, detail)),
)
.into_response(),
}
}
}
impl From<Error> for ApiErr {
fn from(err: Error) -> Self {
tracing::error!("Error: {:?}; root_cause: {}", err, err.root_cause());
ApiErr::Internal("internal server error".to_string(), None)
}
}
impl From<SqlxError> for ApiErr {
fn from(err: SqlxError) -> Self {
match err {
SqlxError::RowNotFound => {
ApiErr::NotFound("Resource not found".into(), None)
}
SqlxError::Database(db_err) => {
if db_err.code().as_deref() == Some("23505") {
ApiErr::BadRequest("数据已存在".into(), None)
} else {
tracing::error!("Database error: {}", db_err);
ApiErr::Internal("Database error".into(), None)
}
}
_ => {
tracing::error!("Database error: {}", err);
ApiErr::Internal("Database error".into(), None)
}
}
}
}
impl From<QueryRejection> for ApiErr {
fn from(rejection: QueryRejection) -> Self {
tracing::warn!("Query parameter error: {}", rejection);
ApiErr::BadRequest(
"Invalid query parameters".to_string(),
Some(serde_json::json!({
"detail": rejection.to_string()
}))
)
}
}
impl From<PathRejection> for ApiErr {
fn from(rejection: PathRejection) -> Self {
tracing::warn!("Path parameter error: {}", rejection);
ApiErr::BadRequest(
"Invalid path parameter".to_string(),
Some(serde_json::json!({
"detail": rejection.to_string()
}))
)
}
}
impl From<JsonRejection> for ApiErr {
fn from(rejection: JsonRejection) -> Self {
tracing::warn!("JSON parsing error: {}", rejection);
ApiErr::BadRequest(
"Invalid JSON format".to_string(),
Some(serde_json::json!({
"detail": rejection.to_string()
}))
)
}
}
impl From<FormRejection> for ApiErr {
fn from(rejection: FormRejection) -> Self {
tracing::warn!("Form data error: {}", rejection);
ApiErr::BadRequest(
"Invalid form data".to_string(),
Some(serde_json::json!({
"detail": rejection.to_string()
}))
)
}
}