use axum::extract::FromRequest;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use chrono::DateTime;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use strum::Display;
use utoipa::ToSchema;
#[derive(Clone, Deserialize, Serialize, Debug, ToSchema)]
#[serde(untagged)]
pub enum AASError {
NotFound { messages: Vec<AASMessage> },
BadRequest { messages: Vec<AASMessage> },
Unauthorized { messages: Vec<AASMessage> },
Forbidden { messages: Vec<AASMessage> },
Internal { messages: Vec<AASMessage> },
}
#[derive(Clone, Deserialize, Serialize, Debug, ToSchema)]
pub struct AASMessage {
#[serde(rename = "messageType")]
pub message_type: AASErrorMessageType,
pub code: String,
#[serde(rename = "correlationId")]
pub correlation_id: String,
pub text: String,
pub timestamp: DateTime<chrono::Utc>,
}
#[derive(Clone, Deserialize, Serialize, Default, Debug, Display, ToSchema)]
pub enum AASErrorMessageType {
#[default]
Undefined,
Info,
Warning,
Error,
Exception,
}
impl IntoResponse for AASError {
fn into_response(self) -> Response {
let (status, err) = match &self {
AASError::NotFound { messages: _ } => (StatusCode::NOT_FOUND, self),
AASError::Internal { messages: _ } => (StatusCode::INTERNAL_SERVER_ERROR, self),
AASError::BadRequest { .. } => (StatusCode::BAD_REQUEST, self),
AASError::Unauthorized { .. } => (StatusCode::UNAUTHORIZED, self),
AASError::Forbidden { .. } => (StatusCode::FORBIDDEN, self),
};
let mut response = (status, AASErrorJson(err.clone())).into_response();
response.extensions_mut().insert(Arc::new(err));
response
}
}
#[derive(FromRequest)]
#[from_request(via(axum::Json), rejection(AASError))]
struct AASErrorJson<T>(T);
impl<T> IntoResponse for AASErrorJson<T>
where
axum::Json<T>: IntoResponse,
{
fn into_response(self) -> Response {
axum::Json(self.0).into_response()
}
}