magnetar/src/web/mod.rs

156 lines
3.9 KiB
Rust

use crate::model::processing::PackError;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use magnetar_calckey_model::{CalckeyCacheError, CalckeyDbError};
use magnetar_common::util::FediverseTagParseError;
use serde::Serialize;
use serde_json::json;
pub mod auth;
#[derive(Debug, Clone, Serialize)]
#[repr(transparent)]
pub struct ErrorCode(pub String);
// This janky hack allows us to use `.error_code()` on enums with strum::IntoStaticStr
pub trait IntoErrorCode {
fn error_code<'a, 'b: 'a>(&'a self) -> ErrorCode
where
&'a Self: Into<&'b str>;
}
impl<T: ?Sized> IntoErrorCode for T {
fn error_code<'a, 'b: 'a>(&'a self) -> ErrorCode
where
&'a Self: Into<&'b str>,
{
ErrorCode(self.into().to_string())
}
}
impl ErrorCode {
pub fn join(&self, other: &str) -> Self {
Self(format!("{}:{}", other, self.0))
}
}
#[derive(Debug)]
pub struct ApiError {
pub status: StatusCode,
pub code: ErrorCode,
pub message: String,
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
(
self.status,
Json(json!({
"status": self.status.as_u16(),
"code": self.code,
"message": self.message,
})),
)
.into_response()
}
}
impl From<FediverseTagParseError> for ApiError {
fn from(err: FediverseTagParseError) -> Self {
Self {
status: StatusCode::BAD_REQUEST,
code: err.error_code(),
message: if cfg!(debug_assertions) {
format!("Fediverse tag parse error: {}", err)
} else {
"Fediverse tag parse error".to_string()
},
}
}
}
impl From<CalckeyDbError> for ApiError {
fn from(err: CalckeyDbError) -> Self {
Self {
status: StatusCode::INTERNAL_SERVER_ERROR,
code: err.error_code(),
message: if cfg!(debug_assertions) {
format!("Database error: {}", err)
} else {
"Database error".to_string()
},
}
}
}
impl From<CalckeyCacheError> for ApiError {
fn from(err: CalckeyCacheError) -> Self {
Self {
status: StatusCode::INTERNAL_SERVER_ERROR,
code: err.error_code(),
message: if cfg!(debug_assertions) {
format!("Cache error: {}", err)
} else {
"Cache error".to_string()
},
}
}
}
impl From<PackError> for ApiError {
fn from(err: PackError) -> Self {
Self {
status: StatusCode::INTERNAL_SERVER_ERROR,
code: err.error_code(),
message: if cfg!(debug_assertions) {
format!("Data transformation error: {}", err)
} else {
"Data transformation error".to_string()
},
}
}
}
#[derive(Debug)]
pub struct ObjectNotFound(pub String);
impl From<&ObjectNotFound> for &str {
fn from(_: &ObjectNotFound) -> Self {
"ObjectNotFound"
}
}
impl From<ObjectNotFound> for ApiError {
fn from(err: ObjectNotFound) -> Self {
Self {
status: StatusCode::NOT_FOUND,
code: err.error_code(),
message: if cfg!(debug_assertions) {
format!("Object not found: {}", err.0)
} else {
"Object not found".to_string()
},
}
}
}
#[derive(Debug)]
pub struct ArgumentOutOfRange(pub String);
impl From<&ArgumentOutOfRange> for &str {
fn from(_: &ArgumentOutOfRange) -> Self {
"ArgumentOutOfRange"
}
}
impl From<ArgumentOutOfRange> for ApiError {
fn from(err: ArgumentOutOfRange) -> Self {
Self {
status: StatusCode::BAD_REQUEST,
code: err.error_code(),
message: format!("Argument out of range: {}", err.0),
}
}
}