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,
17 pub message: String,
18 pub request_id: Option<String>,
19}
20
21impl ApiError {
22 pub fn new(status: StatusCode, message: impl Into<String>) -> Self {
23 Self {
24 status,
25 message: message.into(),
26 request_id: None,
27 }
28 }
29
30 pub fn bad_request(message: impl Into<String>) -> Self {
31 Self::new(StatusCode::BAD_REQUEST, message)
32 }
33 pub fn not_found(message: impl Into<String>) -> Self {
34 Self::new(StatusCode::NOT_FOUND, message)
35 }
36 pub fn internal(message: impl Into<String>) -> Self {
37 Self::new(StatusCode::INTERNAL_SERVER_ERROR, message)
38 }
39
40 pub fn with_request_id(mut self, id: impl Into<String>) -> Self {
42 self.request_id = Some(id.into());
43 self
44 }
45}
46
47impl IntoResponse for ApiError {
48 fn into_response(self) -> Response {
49 let body = json!({
50 "error": self.message,
51 "request_id": self.request_id,
52 });
53 (self.status, Json(body)).into_response()
54 }
55}