111 lines
3.1 KiB
Rust
111 lines
3.1 KiB
Rust
use actix_web::{HttpResponse, ResponseError};
|
|
use serde::Serialize;
|
|
|
|
#[derive(Debug, Serialize)]
|
|
struct ErrorResponse {
|
|
error: String,
|
|
status: u16,
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum ApiError {
|
|
#[error("not found: {0}")]
|
|
NotFound(String),
|
|
|
|
#[error("bad request: {0}")]
|
|
BadRequest(String),
|
|
|
|
#[error("unauthorized: {0}")]
|
|
Unauthorized(String),
|
|
|
|
#[error("forbidden: {0}")]
|
|
Forbidden(String),
|
|
|
|
#[error("rate limited: {0}")]
|
|
TooManyRequests(String),
|
|
|
|
#[error("internal error: {0}")]
|
|
Internal(String),
|
|
}
|
|
|
|
impl ResponseError for ApiError {
|
|
fn error_response(&self) -> HttpResponse {
|
|
let (status, message) = match self {
|
|
ApiError::NotFound(msg) => (actix_web::http::StatusCode::NOT_FOUND, msg.clone()),
|
|
ApiError::BadRequest(msg) => (actix_web::http::StatusCode::BAD_REQUEST, msg.clone()),
|
|
ApiError::Unauthorized(msg) => (actix_web::http::StatusCode::UNAUTHORIZED, msg.clone()),
|
|
ApiError::Forbidden(msg) => (actix_web::http::StatusCode::FORBIDDEN, msg.clone()),
|
|
ApiError::TooManyRequests(msg) => {
|
|
tracing::warn!(error = %msg, "rate limited");
|
|
(actix_web::http::StatusCode::TOO_MANY_REQUESTS, msg.clone())
|
|
}
|
|
ApiError::Internal(msg) => {
|
|
tracing::error!(error = %msg, "internal error");
|
|
(
|
|
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
|
|
msg.clone(),
|
|
)
|
|
}
|
|
};
|
|
|
|
HttpResponse::build(status).json(ErrorResponse {
|
|
error: message,
|
|
status: status.as_u16(),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<shanty_db::DbError> for ApiError {
|
|
fn from(e: shanty_db::DbError) -> Self {
|
|
match e {
|
|
shanty_db::DbError::NotFound(msg) => ApiError::NotFound(msg),
|
|
other => ApiError::Internal(other.to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<shanty_watch::WatchError> for ApiError {
|
|
fn from(e: shanty_watch::WatchError) -> Self {
|
|
ApiError::Internal(e.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<shanty_search::SearchError> for ApiError {
|
|
fn from(e: shanty_search::SearchError) -> Self {
|
|
ApiError::Internal(e.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<shanty_dl::DlError> for ApiError {
|
|
fn from(e: shanty_dl::DlError) -> Self {
|
|
match e {
|
|
shanty_dl::DlError::RateLimited(msg) => ApiError::TooManyRequests(msg),
|
|
other => ApiError::Internal(other.to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<shanty_index::IndexError> for ApiError {
|
|
fn from(e: shanty_index::IndexError) -> Self {
|
|
ApiError::Internal(e.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<shanty_tag::TagError> for ApiError {
|
|
fn from(e: shanty_tag::TagError) -> Self {
|
|
ApiError::Internal(e.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<shanty_data::DataError> for ApiError {
|
|
fn from(e: shanty_data::DataError) -> Self {
|
|
ApiError::Internal(e.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<shanty_org::OrgError> for ApiError {
|
|
fn from(e: shanty_org::OrgError) -> Self {
|
|
ApiError::Internal(e.to_string())
|
|
}
|
|
}
|