1use axum::{
7 Json,
8 http::StatusCode,
9 response::{IntoResponse, Response},
10};
11use serde::Serialize;
12use thiserror::Error;
13
14#[derive(Error, Debug)]
17pub enum ApiError {
18 #[error("bad request: {0}")]
19 BadRequest(String),
20 #[error("not found")]
21 NotFound,
22 #[error("internal server error")]
23 InternalServerError,
24}
25
26impl From<anyhow::Error> for ApiError {
27 fn from(err: anyhow::Error) -> Self {
28 tracing::error!("internal server error: {err}");
29 ApiError::InternalServerError
30 }
31}
32
33impl IntoResponse for ApiError {
34 fn into_response(self) -> Response {
35 let status_code = match self {
36 ApiError::BadRequest(_) => StatusCode::BAD_REQUEST,
37 ApiError::NotFound => StatusCode::NOT_FOUND,
38 ApiError::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
39 };
40
41 let body = Json(ErrorResponse {
42 error_code: status_code.as_u16().to_string(),
43 error_message: self.to_string(),
44 });
45
46 (status_code, body).into_response()
47 }
48}
49
50#[derive(Clone, Debug, Serialize)]
52pub(crate) struct ErrorResponse {
53 error_code: String,
54 error_message: String,
55}