65 lines
1.8 KiB
Rust
65 lines
1.8 KiB
Rust
use std::convert::Infallible;
|
|
|
|
use axum::{response::IntoResponse, body::{Full, Bytes}, Json};
|
|
use hyper::StatusCode;
|
|
use serde::{Serializer, Serialize};
|
|
use thiserror::Error;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum ApplicationError {
|
|
#[error("File read error: {0}")]
|
|
Read(#[from] std::io::Error),
|
|
#[error("Deserialize error: {0}")]
|
|
Deserialize(#[from] toml::de::Error),
|
|
#[error("Database connection error: {0}")]
|
|
Database(#[from] sibyl::Error),
|
|
#[error("Axum error: {0}")]
|
|
Axum(#[from] hyper::Error),
|
|
}
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum ServiceError {
|
|
#[error("SQL error: {0}")]
|
|
Database(#[from] sibyl::Error),
|
|
#[error("Response code: {0}")]
|
|
ErrorResponse(StatusCode, Option<String>),
|
|
}
|
|
|
|
fn serialize_status<S>(x: &StatusCode, s: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
s.serialize_u16(x.as_u16())
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct ErrorResponse {
|
|
#[serde(serialize_with = "serialize_status")]
|
|
pub status: StatusCode,
|
|
pub error: String,
|
|
}
|
|
|
|
impl IntoResponse for ServiceError {
|
|
type Body = Full<Bytes>;
|
|
|
|
type BodyError = Infallible;
|
|
|
|
fn into_response(self) -> axum::http::Response<Self::Body> {
|
|
let res = match self {
|
|
ServiceError::Database(err) => ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Some(err.to_string())),
|
|
ServiceError::ErrorResponse(code, reason) => ErrorResponse::new(code, reason),
|
|
};
|
|
let status = res.status;
|
|
(status, Json(res)).into_response()
|
|
}
|
|
}
|
|
|
|
impl ErrorResponse {
|
|
fn new(status: StatusCode, message: Option<String>) -> Self {
|
|
let reason = status.canonical_reason().unwrap_or_default();
|
|
Self {
|
|
status,
|
|
error: message.unwrap_or_else(|| reason.to_string()),
|
|
}
|
|
}
|
|
} |