use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("not found: {0}")]
NotFound(String),
#[error("bad request: {0}")]
BadRequest(String),
#[error("{0}")]
PreconditionRequired(String),
#[error("request body too large")]
TooLarge,
#[error("upstream error: {0}")]
Upstream(String),
#[error("database error: {0}")]
Database(#[from] rusqlite::Error),
#[error("object storage error: {0}")]
Storage(#[from] object_store::Error),
#[error("internal error: {0}")]
Internal(String),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let status = match &self {
AppError::NotFound(_) => StatusCode::NOT_FOUND,
AppError::BadRequest(_) => StatusCode::BAD_REQUEST,
AppError::PreconditionRequired(_) => StatusCode::PRECONDITION_REQUIRED,
AppError::TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
AppError::Upstream(_) => StatusCode::BAD_GATEWAY,
AppError::Database(_) | AppError::Storage(_) | AppError::Internal(_) => {
StatusCode::INTERNAL_SERVER_ERROR
}
};
if status.is_server_error() {
tracing::error!(error = %self, "request failed");
return (status, "internal server error").into_response();
}
(status, self.to_string()).into_response()
}
}