1use std::fmt::{Display, Formatter, Debug};
2use std::error::Error;
3use serde::Serialize;
4pub use actix_error_derive::AsApiError;
5
6#[derive(Debug, Clone, Serialize)]
8pub struct ApiError {
9 pub kind: String,
11 #[serde(skip_serializing)]
13 pub code: u16,
14 pub message: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub details: Option<serde_json::Value>,
19}
20
21impl ApiError {
22 pub fn new(
31 code: u16,
32 kind: &str,
33 message: String,
34 details: Option<serde_json::Value>,
35 ) -> Self {
36 Self {
37 kind: kind.to_string(),
38 message,
39 code,
40 details,
41 }
42 }
43}
44
45pub trait AsApiErrorTrait {
47 fn as_api_error(&self) -> ApiError;
49}
50
51impl Display for ApiError {
52 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
53 write!(f, "{}: {}", self.kind, self.message)
54 }
55}
56
57impl Error for ApiError {}
58
59impl actix_web::ResponseError for ApiError {
60 fn status_code(&self) -> actix_web::http::StatusCode {
61 actix_web::http::StatusCode::from_u16(self.code)
62 .unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
63 }
64
65 fn error_response(&self) -> actix_web::HttpResponse {
66 actix_web::HttpResponse::build(self.status_code()).json(self)
67 }
68}