1use axum::http::StatusCode;
9use axum::response::{IntoResponse, Response};
10use axum::Json;
11use serde_json::json;
12
13#[derive(Debug, Clone)]
15pub struct ApiError {
16 pub status: StatusCode,
18 pub message: String,
20 pub request_id: Option<String>,
22}
23
24impl ApiError {
25 pub fn new(status: StatusCode, message: impl Into<String>) -> Self {
27 Self {
28 status,
29 message: message.into(),
30 request_id: None,
31 }
32 }
33
34 pub fn bad_request(message: impl Into<String>) -> Self {
36 Self::new(StatusCode::BAD_REQUEST, message)
37 }
38 pub fn not_found(message: impl Into<String>) -> Self {
40 Self::new(StatusCode::NOT_FOUND, message)
41 }
42 pub fn internal(message: impl Into<String>) -> Self {
44 Self::new(StatusCode::INTERNAL_SERVER_ERROR, message)
45 }
46
47 pub fn with_request_id(mut self, id: impl Into<String>) -> Self {
49 self.request_id = Some(id.into());
50 self
51 }
52}
53
54impl IntoResponse for ApiError {
55 fn into_response(self) -> Response {
56 let body = json!({
57 "error": self.message,
58 "request_id": self.request_id,
59 });
60 (self.status, Json(body)).into_response()
61 }
62}