1use std::fmt::Display;
3
4use axum::http::StatusCode;
5
6use axum::response::{IntoResponse, Response};
7
8use miette::Diagnostic;
9use serde::Serialize;
10
11use crate::reply;
12
13const MESSAGE_NOT_FOUND: &str = "not found";
14const MESSAGE_FORBIDDEN: &str = "forbidden";
15const MESSAGE_INTERNAL_SERVER_ERROR: &str = "internal server error";
16
17#[derive(Debug, Diagnostic, Serialize)]
18#[serde(untagged)]
19pub enum HTTPError {
20 BadRequest {
21 error: String,
22 },
23 Forbidden,
24 NotFound,
25 InternalServerError {
26 error: String,
27 backtrace: Option<String>,
28 },
29}
30
31impl Display for HTTPError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 match self {
34 Self::BadRequest { error } => write!(f, "bad request: {}", error),
35 Self::Forbidden => write!(f, "forbidden"),
36 Self::NotFound => write!(f, "not found"),
37 Self::InternalServerError {
38 error,
39 backtrace: Some(backtrace),
40 } => write!(f, "internal server error: {}\n{}", error, backtrace),
41 Self::InternalServerError {
42 error,
43 backtrace: None,
44 } => write!(f, "internal server error: {}", error),
45 }
46 }
47}
48
49impl std::error::Error for HTTPError {}
50
51impl HTTPError {
52 pub fn bad_request<S: ToString>(s: S) -> Self {
53 Self::BadRequest {
54 error: s.to_string(),
55 }
56 }
57
58 pub fn internal_server_error<E: ToString>(e: E) -> Self {
59 Self::InternalServerError {
60 error: e.to_string(),
61 backtrace: None, }
63 }
64}
65
66impl IntoResponse for HTTPError {
67 fn into_response(self) -> Response {
68 match self {
69 Self::BadRequest { error } => reply::error(error, StatusCode::BAD_REQUEST),
70 Self::Forbidden => reply::error(MESSAGE_FORBIDDEN, StatusCode::FORBIDDEN),
71 Self::NotFound => reply::error(MESSAGE_NOT_FOUND, StatusCode::NOT_FOUND),
72 Self::InternalServerError {
73 ref error,
74 ref backtrace,
75 } => {
76 if let Some(backtrace) = backtrace {
77 tracing::error!("{error}\n{backtrace}");
78 } else {
79 tracing::error!("{error}");
80 }
81 reply::error(
82 MESSAGE_INTERNAL_SERVER_ERROR,
83 StatusCode::INTERNAL_SERVER_ERROR,
84 )
85 }
86 }
87 }
88}