use axum::Json;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
#[derive(Debug, Clone)]
pub struct ApiError {
pub status: StatusCode,
pub message: String,
}
impl ApiError {
pub fn bad_request(message: impl Into<String>) -> Self {
Self {
status: StatusCode::BAD_REQUEST,
message: message.into(),
}
}
pub fn not_found(message: impl Into<String>) -> Self {
Self {
status: StatusCode::NOT_FOUND,
message: message.into(),
}
}
pub fn internal(message: impl Into<String>) -> Self {
Self {
status: StatusCode::INTERNAL_SERVER_ERROR,
message: message.into(),
}
}
pub fn forbidden(message: impl Into<String>) -> Self {
Self {
status: StatusCode::FORBIDDEN,
message: message.into(),
}
}
pub fn conflict(message: impl Into<String>) -> Self {
Self {
status: StatusCode::CONFLICT,
message: message.into(),
}
}
}
impl From<std::io::Error> for ApiError {
fn from(e: std::io::Error) -> Self {
ApiError::internal(e.to_string())
}
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
use zagens_core::error_taxonomy::ErrorEnvelope;
let status_recoverable = matches!(
self.status,
StatusCode::INTERNAL_SERVER_ERROR
| StatusCode::BAD_GATEWAY
| StatusCode::SERVICE_UNAVAILABLE
| StatusCode::GATEWAY_TIMEOUT
| StatusCode::REQUEST_TIMEOUT
| StatusCode::TOO_MANY_REQUESTS
);
let mut envelope = ErrorEnvelope::classify(&self.message, status_recoverable);
envelope.recoverable = envelope.recoverable || status_recoverable;
let body = envelope.to_wire_error_body(self.status.as_u16());
(self.status, Json(body)).into_response()
}
}