1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::collections::HashMap;
use actix_web::http::StatusCode;

pub use actix_error_derive::AsApiError;
use serde::Serialize;

pub mod translate;

#[derive(Debug, Clone, Serialize)]
pub struct ApiError {
    pub kind: String,
    #[serde(skip_serializing)]
    pub code: u16,
    #[serde(skip_serializing)]
    pub messages: HashMap<String, String>,
    message_fr: String,
    message_en: String,
    origin: String,
}

impl ApiError {
    pub fn new(code: u16, kind: &str, messages: HashMap<String, String>) -> Self {
        let message_en = messages.get("en").unwrap_or(&String::new()).to_string();
        let message_fr = messages.get("fr").unwrap_or(&String::new()).to_string();
        Self {
            kind: kind.to_string(),
            code,
            messages,
            message_fr,
            message_en,
            origin: String::new(),
        }
    }
}

pub trait AsApiError {
    fn as_api_error(&self) -> ApiError;
}

impl std::fmt::Display for ApiError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{} : {:?}", self.kind, self.messages)
    }
}
#[cfg(feature = "po")]
use translate::Translation;

impl actix_web::ResponseError for ApiError {
    fn status_code(&self) -> StatusCode {
        StatusCode::from_u16(self.code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
    }

    fn error_response(&self) -> actix_web::HttpResponse {
        actix_web::HttpResponse::build(self.status_code()).json(self)
    }
}
#[cfg(feature = "po")]
#[derive(AsApiError)]
#[cfg_attr(all(feature = "json", feature = "po"), msg_path = "locales/")]
#[cfg_attr(all(not(feature = "json"), feature = "po"), po_directory = "locales/")]
pub enum ErrorEn {
    #[error(status = "BadRequest", msg_id = "invalid_password")]
    InvalidPassword,
    #[error(code = 404, msg_id = "invalid_id")]
    InvalidId(u32),
    #[error(code = 500, msg_id = "named_error")]
    NamedError { name: String, age: u32 },
    #[error(code = 500)]
    NamedError2(Translation),
}

#[test]
#[cfg(all(feature = "po", feature = "actix"))]
fn default() {
    let e = ErrorEn::InvalidPassword;
    println!(
        "Error::as_api_error() = {:?}",
        serde_json::to_string(&e.as_api_error()).unwrap()
    );
    let e = ErrorEn::InvalidId(42);
    println!(
        "Error::as_api_error() = {:?}",
        serde_json::to_string(&e.as_api_error()).unwrap()
    );
    let e = ErrorEn::NamedError {
        name: "John".to_string(),
        age: 42,
    };
    println!(
        "Error::as_api_error() = {:?}",
        serde_json::to_string(&e.as_api_error()).unwrap()
    );
    let e = ErrorEn::NamedError2(tr! {
        "en" => "Hello",
        "fr" => "Bonjour",
    });
    println!(
        "Error::as_api_error() = {:?}",
        serde_json::to_string(&e.as_api_error()).unwrap()
    );
}