medullah_web/enums/
app_message.rs

1use crate::contracts::ResponseCodeContract;
2use crate::enums::ResponseCode;
3#[cfg(feature = "reqwest")]
4use crate::helpers::reqwest::ReqwestResponseError;
5use crate::helpers::responder::Responder;
6use log::error;
7#[cfg(feature = "multipart")]
8use medullah_multipart::{ErrorMessage as MultipartErrorMessage, MultipartError};
9use ntex::http::error::BlockingError;
10use ntex::http::StatusCode;
11use ntex::web::{HttpRequest, WebResponseError};
12use std::fmt::{Debug, Display, Formatter};
13use std::io;
14use std::ops::Deref;
15
16pub enum AppMessage {
17    UnAuthorized,
18    Forbidden,
19    InternalServerError,
20    InternalServerErrorMessage(&'static str),
21    Anyhow(anyhow::Error),
22    IoError(io::Error),
23    UuidError(uuid::Error),
24    Redirect(&'static str),
25    SuccessMessage(&'static str),
26    SuccessMessageString(String),
27    WarningMessage(&'static str),
28    WarningMessageString(String),
29    HttpClientError(String, String),
30    #[cfg(feature = "hmac")]
31    HmacError(hmac::digest::InvalidLength),
32    UnAuthorizedMessage(&'static str),
33    UnAuthorizedMessageString(String),
34    ForbiddenMessage(&'static str),
35    ForbiddenMessageString(String),
36    #[cfg(feature = "validator")]
37    FormValidationError(validator::ValidationErrors),
38    EntityNotFound(String),
39    #[cfg(feature = "reqwest")]
40    ReqwestError(reqwest::Error),
41    #[cfg(feature = "reqwest")]
42    ReqwestResponseError(ReqwestResponseError),
43    #[cfg(feature = "mailer")]
44    MailerError(reqwest::Error),
45    #[cfg(feature = "multipart")]
46    MultipartError(medullah_multipart::MultipartError),
47    #[cfg(feature = "strum")]
48    StrumParseError(strum::ParseError),
49    SerdeError(serde_json::Error),
50    SerdeError500(serde_json::Error),
51    #[cfg(feature = "base64")]
52    Base64Error(base64::DecodeError),
53    JoinError(tokio::task::JoinError),
54    #[cfg(feature = "jwt")]
55    JwtError(jsonwebtoken::errors::Error),
56    #[cfg(feature = "crypto")]
57    ArgonError(argon2::Error),
58    StrUtf8Error(std::str::Utf8Error),
59    FromUtf8Error(std::string::FromUtf8Error),
60    ChronoParseError(chrono::ParseError),
61    #[cfg(feature = "rabbitmq")]
62    RabbitmqError(lapin::Error),
63    #[cfg(feature = "redis")]
64    RedisError(redis::RedisError),
65    #[cfg(feature = "redis")]
66    RedisPoolError(deadpool::managed::PoolError<redis::RedisError>),
67    #[cfg(feature = "rabbitmq")]
68    RmqPoolError(deadpool::managed::PoolError<lapin::Error>),
69    ErrorMessage(String, StatusCode),
70    PayloadError(ntex::http::error::PayloadError),
71    BlockingNtexErrorInnerBoxed(BlockingError<Box<Self>>),
72    BlockingNtexErrorOuterBoxed(Box<BlockingError<Self>>),
73    BlockingNtexIoError(BlockingError<io::Error>),
74    BlockingErrorCanceled,
75    #[cfg(feature = "database")]
76    R2d2Error(r2d2::Error),
77    #[cfg(feature = "database")]
78    DatabaseError(diesel::result::Error),
79}
80
81fn format_message(status: &AppMessage, f: &mut Formatter<'_>) -> std::fmt::Result {
82    f.write_str(get_message(status).as_str())
83}
84
85fn get_message(status: &AppMessage) -> String {
86    match status {
87        AppMessage::Anyhow(err) => err.to_string(),
88        AppMessage::UuidError(err) => err.to_string(),
89        AppMessage::UnAuthorized => {
90            String::from("You are not authorized to access requested resource(s)")
91        }
92        AppMessage::Forbidden => {
93            String::from("You don't have sufficient permissions to access requested resource(s)")
94        }
95        AppMessage::Redirect(url) => format!("Redirecting to '{}'...", url),
96        AppMessage::EntityNotFound(entity) => format!("Such {} does not exits", entity),
97        #[cfg(feature = "database")]
98        AppMessage::R2d2Error(error) => error.to_string(),
99        #[cfg(feature = "rabbitmq")]
100        AppMessage::RmqPoolError(error) => error.to_string(),
101        #[cfg(feature = "jwt")]
102        AppMessage::JwtError(err) => err.to_string(),
103        #[cfg(feature = "crypto")]
104        AppMessage::ArgonError(err) => err.to_string(),
105        #[cfg(feature = "multipart")]
106        AppMessage::MultipartError(err) => err.to_string(),
107        AppMessage::IoError(error) => error.to_string(),
108        AppMessage::SerdeError(error) => error.to_string(),
109        AppMessage::SerdeError500(error) => error.to_string(),
110        #[cfg(feature = "rabbitmq")]
111        AppMessage::RabbitmqError(error) => error.to_string(),
112        #[cfg(feature = "redis")]
113        AppMessage::RedisError(error) => error.to_string(),
114        #[cfg(feature = "redis")]
115        AppMessage::RedisPoolError(error) => error.to_string(),
116        AppMessage::JoinError(error) => error.to_string(),
117        #[cfg(feature = "reqwest")]
118        AppMessage::ReqwestError(error) => error.to_string(),
119        #[cfg(feature = "reqwest")]
120        AppMessage::ReqwestResponseError(error) => error.body().to_owned(),
121        #[cfg(feature = "mailer")]
122        AppMessage::MailerError(error) => error.to_string(),
123        #[cfg(feature = "base64")]
124        AppMessage::Base64Error(error) => error.to_string(),
125        AppMessage::StrUtf8Error(error) => error.to_string(),
126        AppMessage::FromUtf8Error(error) => error.to_string(),
127        AppMessage::ChronoParseError(error) => error.to_string(),
128        AppMessage::BlockingNtexErrorInnerBoxed(error) => error.to_string(),
129        AppMessage::BlockingNtexErrorOuterBoxed(error) => error.to_string(),
130        AppMessage::BlockingNtexIoError(error) => error.to_string(),
131        AppMessage::PayloadError(error) => error.to_string(),
132        AppMessage::WarningMessage(message)
133        | AppMessage::SuccessMessage(message)
134        | AppMessage::ForbiddenMessage(message)
135        | AppMessage::UnAuthorizedMessage(message)
136        | AppMessage::InternalServerErrorMessage(message) => message.to_string(),
137        AppMessage::WarningMessageString(message)
138        | AppMessage::SuccessMessageString(message)
139        | AppMessage::UnAuthorizedMessageString(message)
140        | AppMessage::ForbiddenMessageString(message)
141        | AppMessage::HttpClientError(message, _)
142        | AppMessage::ErrorMessage(message, _) => message.to_string(),
143        #[cfg(feature = "database")]
144        AppMessage::DatabaseError(err) => match err {
145            diesel::result::Error::NotFound => String::from("Such entity not found"),
146            diesel::result::Error::DatabaseError(err, info) => match err {
147                diesel::result::DatabaseErrorKind::UniqueViolation => {
148                    error!(
149                        "conflict error({:?}): {} [::] {:?}",
150                        err,
151                        info.message(),
152                        info.details()
153                    );
154
155                    "conflicted with existing entity".to_string()
156                }
157                _ => {
158                    error!(
159                        "database kind-level-error({:?}): {} [::] {:?}",
160                        err,
161                        info.message(),
162                        info.details()
163                    );
164                    "something went wrong".to_string()
165                }
166            },
167            _ => {
168                error!("database error: {:?}", err);
169                String::from("Something went wrong")
170            }
171        },
172        #[cfg(feature = "hmac")]
173        AppMessage::HmacError(message) => message.to_string(),
174        #[cfg(feature = "strum")]
175        AppMessage::StrumParseError(message) => message.to_string(),
176        #[cfg(feature = "validator")]
177        AppMessage::FormValidationError(e) => String::from(e.to_string().as_str()),
178        _ => String::from("Internal Server Error"),
179    }
180}
181
182pub fn get_middleware_level_message(app: &AppMessage) -> String {
183    match app {
184        AppMessage::WarningMessage(message) => message.to_string(),
185        AppMessage::WarningMessageString(message) => message.to_owned(),
186        AppMessage::SuccessMessage(message) => message.to_string(),
187        AppMessage::SuccessMessageString(message) => message.to_owned(),
188        AppMessage::UnAuthorizedMessage(message) => message.to_string(),
189        AppMessage::UnAuthorizedMessageString(message) => message.to_owned(),
190        AppMessage::ForbiddenMessage(message) => message.to_string(),
191        AppMessage::ForbiddenMessageString(message) => message.to_owned(),
192        AppMessage::InternalServerErrorMessage(message) => message.to_string(),
193        AppMessage::Anyhow(message) => message.to_string(),
194        #[cfg(feature = "jwt")]
195        AppMessage::JwtError(_) => "failed to authenticate your jwt token".to_string(),
196        _ => {
197            error!("[middleware-level-error] {:?}", app);
198            String::from("Something isn't right, our engineers are on it")
199        }
200    }
201}
202
203fn send_response(message: &AppMessage) -> ntex::web::HttpResponse {
204    match message {
205        AppMessage::EntityNotFound(entity) => Responder::entity_not_found_message(entity),
206        AppMessage::Redirect(url) => ntex::web::HttpResponse::Found()
207            .header(
208                ntex::http::header::HeaderName::from_static("Location"),
209                ntex::http::header::HeaderValue::from_static(url),
210            )
211            .finish()
212            .into_body(),
213        AppMessage::Anyhow(err) => {
214            log::error!("Anyhow Error: {}", err);
215            Responder::internal_server_error()
216        }
217        AppMessage::IoError(message) => {
218            log::error!("IO Error: {}", message);
219            Responder::internal_server_error()
220        }
221        #[cfg(feature = "database")]
222        AppMessage::R2d2Error(message) => {
223            log::error!("R2d2 Error: {}", message);
224            Responder::internal_server_error()
225        }
226        #[cfg(feature = "jwt")]
227        AppMessage::JwtError(message) => {
228            log::error!("Jwt Error: {}", message);
229            Responder::message("invalid jwt token", ResponseCode::Unauthorized)
230        }
231        #[cfg(feature = "crypto")]
232        AppMessage::ArgonError(message) => {
233            log::error!("Argon Error: {}", message);
234            Responder::internal_server_error()
235        }
236        #[cfg(feature = "rabbitmq")]
237        AppMessage::RabbitmqError(message) => {
238            log::error!("Rabbitmq Error: {}", message);
239            Responder::internal_server_error()
240        }
241        #[cfg(feature = "redis")]
242        AppMessage::RedisError(message) => {
243            log::error!("Redis Error: {}", message);
244            Responder::internal_server_error()
245        }
246        #[cfg(feature = "redis")]
247        AppMessage::RedisPoolError(message) => {
248            log::error!("Redis Pool Error: {}", message);
249            Responder::internal_server_error()
250        }
251        #[cfg(feature = "rabbitmq")]
252        AppMessage::RmqPoolError(message) => {
253            log::error!("RabbitMQ Pool Error: {}", message);
254            Responder::internal_server_error()
255        }
256        #[cfg(feature = "reqwest")]
257        AppMessage::ReqwestError(message) => {
258            log::error!("Http Client(Reqwest) Error: {}", message);
259            Responder::internal_server_error()
260        }
261        #[cfg(feature = "reqwest")]
262        AppMessage::ReqwestResponseError(err) => {
263            log::error!("Http Client(Reqwest) Error[{}]: {}", err.code(), err.body());
264            Responder::internal_server_error()
265        }
266        AppMessage::StrUtf8Error(message) => {
267            log::error!("Str-Utf8 Conversion Error: {:?}", message);
268            Responder::internal_server_error()
269        }
270        AppMessage::FromUtf8Error(message) => {
271            log::error!("Utf8 Conversion Error: {:?}", message);
272            Responder::internal_server_error()
273        }
274        #[cfg(feature = "base64")]
275        AppMessage::Base64Error(message) => {
276            log::error!("Base64 Error: {:?}", message);
277            Responder::internal_server_error()
278        }
279        #[cfg(feature = "strum")]
280        AppMessage::StrumParseError(message) => {
281            log::error!("Strum Parse Error: {:?}", message);
282            Responder::internal_server_error()
283        }
284        AppMessage::SerdeError(message) => {
285            log::error!("Serde Error: {:?}", message);
286            Responder::message(&message.to_string(), ResponseCode::BadRequest)
287        }
288        AppMessage::SerdeError500(message) => {
289            log::error!("Serde Error: {}", message);
290            Responder::internal_server_error()
291        }
292        AppMessage::BlockingNtexErrorInnerBoxed(message) => {
293            log::error!("Blocking Error: {}", message);
294            match message {
295                BlockingError::Error(error) => send_response(error),
296                BlockingError::Canceled => Responder::internal_server_error(),
297            }
298        }
299        AppMessage::BlockingNtexErrorOuterBoxed(message) => {
300            log::error!("Blocking Error: {}", message);
301            match message.deref() {
302                BlockingError::Error(error) => send_response(error),
303                BlockingError::Canceled => Responder::internal_server_error(),
304            }
305        }
306        AppMessage::BlockingNtexIoError(message) => {
307            log::error!("Blocking IO Error: {}", message);
308            Responder::internal_server_error()
309        }
310        AppMessage::PayloadError(message) => {
311            log::error!("Payload Extraction Error: {}", message);
312            Responder::internal_server_error()
313        }
314        AppMessage::InternalServerErrorMessage(message) => {
315            log::error!("Internal Server Error: {}", message);
316            Responder::internal_server_error()
317        }
318        AppMessage::SuccessMessage(message) => Responder::ok_message(message),
319        AppMessage::SuccessMessageString(message) => Responder::ok_message(message),
320        AppMessage::ErrorMessage(message, status) => {
321            Responder::message(message, ResponseCode::from_status(*status))
322        }
323        AppMessage::UnAuthorized => {
324            Responder::message(&message.message(), ResponseCode::Unauthorized)
325        }
326        AppMessage::UnAuthorizedMessage(message) => {
327            Responder::message(message, ResponseCode::Unauthorized)
328        }
329        AppMessage::UnAuthorizedMessageString(message) => {
330            Responder::message(message, ResponseCode::Unauthorized)
331        }
332        AppMessage::Forbidden => Responder::message(&message.message(), ResponseCode::Forbidden),
333        AppMessage::ForbiddenMessage(message) => {
334            Responder::message(message, ResponseCode::Forbidden)
335        }
336        AppMessage::ForbiddenMessageString(message) => {
337            Responder::message(message, ResponseCode::Forbidden)
338        }
339        AppMessage::ChronoParseError(error) => {
340            let message = error.to_string();
341            log::error!("Failed To Parse DateTime: {}", message);
342            Responder::message(&message, ResponseCode::BadRequest)
343        }
344        #[cfg(feature = "validator")]
345        AppMessage::FormValidationError(e) => {
346            Responder::send_msg(e, ResponseCode::BadRequest, "Validation Error")
347        }
348        #[cfg(feature = "multipart")]
349        AppMessage::MultipartError(e) => {
350            Responder::send_msg(e.to_string(), ResponseCode::BadRequest, "File Upload Error")
351        }
352        #[cfg(feature = "database")]
353        AppMessage::DatabaseError(err) => match err {
354            diesel::result::Error::NotFound => {
355                Responder::not_found_message("Such entity not found")
356            }
357            diesel::result::Error::DatabaseError(err, _) => {
358                error!("database error: {:?}", err);
359                match err {
360                    diesel::result::DatabaseErrorKind::UniqueViolation => {
361                        Responder::message(&message.message(), ResponseCode::BadRequest)
362                    }
363                    _ => Responder::internal_server_error(),
364                }
365            }
366            _ => {
367                error!("database error: {:?}", err);
368                Responder::internal_server_error_message(&message.message())
369            }
370        },
371        #[cfg(feature = "hmac")]
372        AppMessage::HmacError(err) => {
373            error!("{:?}", err);
374            Responder::internal_server_error()
375        }
376        _ => Responder::bad_req_message(get_message(message).as_str()),
377    }
378}
379
380fn get_status_code(status: &AppMessage) -> StatusCode {
381    #[cfg(feature = "database")]
382    use diesel::result::Error as DieselError;
383
384    match status {
385        AppMessage::SuccessMessage(_) | AppMessage::SuccessMessageString(_) => StatusCode::OK,
386        AppMessage::UuidError(_)
387        | AppMessage::WarningMessage(_)
388        | AppMessage::WarningMessageString(_)
389        | AppMessage::SerdeError(_)
390        | AppMessage::ChronoParseError(_) => StatusCode::BAD_REQUEST,
391        AppMessage::EntityNotFound(_msg) => StatusCode::NOT_FOUND,
392        #[cfg(feature = "multipart")]
393        AppMessage::MultipartError(err) => match err {
394            MultipartError::ValidationError(err) => match err.error {
395                MultipartErrorMessage::InvalidFileExtension(_)
396                | MultipartErrorMessage::InvalidContentType(_) => {
397                    StatusCode::UNSUPPORTED_MEDIA_TYPE
398                }
399                _ => StatusCode::BAD_REQUEST,
400            },
401            _ => StatusCode::BAD_REQUEST,
402        },
403        #[cfg(feature = "database")]
404        AppMessage::DatabaseError(DieselError::NotFound) => StatusCode::NOT_FOUND,
405        #[cfg(feature = "database")]
406        AppMessage::DatabaseError(DieselError::DatabaseError(
407            diesel::result::DatabaseErrorKind::UniqueViolation,
408            _,
409        )) => StatusCode::CONFLICT,
410        #[cfg(feature = "jwt")]
411        AppMessage::JwtError(_) => StatusCode::UNAUTHORIZED,
412        #[cfg(feature = "validator")]
413        AppMessage::FormValidationError(_) => StatusCode::BAD_REQUEST,
414        AppMessage::ErrorMessage(_, status) => *status,
415        AppMessage::UnAuthorized
416        | AppMessage::UnAuthorizedMessage(_)
417        | AppMessage::UnAuthorizedMessageString(_) => StatusCode::UNAUTHORIZED,
418        AppMessage::Forbidden
419        | AppMessage::ForbiddenMessage(_)
420        | AppMessage::ForbiddenMessageString(_) => StatusCode::FORBIDDEN,
421        _ => StatusCode::INTERNAL_SERVER_ERROR, // all database-related errors are 500
422    }
423}
424
425impl Debug for AppMessage {
426    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
427        format_message(self, f)
428    }
429}
430
431#[cfg(feature = "validator")]
432impl From<validator::ValidationErrors> for AppMessage {
433    fn from(value: validator::ValidationErrors) -> Self {
434        AppMessage::FormValidationError(value)
435    }
436}
437
438impl Display for AppMessage {
439    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
440        format_message(self, f)
441    }
442}
443
444impl From<anyhow::Error> for AppMessage {
445    fn from(value: anyhow::Error) -> Self {
446        AppMessage::Anyhow(value)
447    }
448}
449
450impl From<io::Error> for AppMessage {
451    fn from(value: io::Error) -> Self {
452        AppMessage::IoError(value)
453    }
454}
455
456#[cfg(feature = "jwt")]
457impl From<jsonwebtoken::errors::Error> for AppMessage {
458    fn from(value: jsonwebtoken::errors::Error) -> Self {
459        AppMessage::JwtError(value)
460    }
461}
462
463#[cfg(feature = "crypto")]
464impl From<argon2::Error> for AppMessage {
465    fn from(value: argon2::Error) -> Self {
466        AppMessage::ArgonError(value)
467    }
468}
469
470#[cfg(feature = "reqwest")]
471impl From<reqwest::Error> for AppMessage {
472    fn from(value: reqwest::Error) -> Self {
473        AppMessage::ReqwestError(value)
474    }
475}
476
477impl From<ntex::http::error::PayloadError> for AppMessage {
478    fn from(value: ntex::http::error::PayloadError) -> Self {
479        AppMessage::PayloadError(value)
480    }
481}
482
483#[cfg(feature = "database")]
484impl From<r2d2::Error> for AppMessage {
485    fn from(value: r2d2::Error) -> Self {
486        AppMessage::R2d2Error(value)
487    }
488}
489
490impl From<uuid::Error> for AppMessage {
491    fn from(value: uuid::Error) -> Self {
492        AppMessage::UuidError(value)
493    }
494}
495
496impl From<tokio::task::JoinError> for AppMessage {
497    fn from(value: tokio::task::JoinError) -> Self {
498        AppMessage::JoinError(value)
499    }
500}
501
502impl From<BlockingError<AppMessage>> for AppMessage {
503    fn from(value: BlockingError<AppMessage>) -> Self {
504        AppMessage::BlockingNtexErrorOuterBoxed(Box::new(value))
505    }
506}
507
508impl From<BlockingError<Box<AppMessage>>> for AppMessage {
509    fn from(value: BlockingError<Box<AppMessage>>) -> Self {
510        AppMessage::BlockingNtexErrorInnerBoxed(value)
511    }
512}
513
514impl From<BlockingError<io::Error>> for AppMessage {
515    fn from(value: BlockingError<io::Error>) -> Self {
516        AppMessage::BlockingNtexIoError(value)
517    }
518}
519
520#[cfg(feature = "rabbitmq")]
521impl From<lapin::Error> for AppMessage {
522    fn from(value: lapin::Error) -> Self {
523        AppMessage::RabbitmqError(value)
524    }
525}
526
527#[cfg(feature = "redis")]
528impl From<redis::RedisError> for AppMessage {
529    fn from(value: redis::RedisError) -> Self {
530        AppMessage::RedisError(value)
531    }
532}
533
534#[cfg(feature = "rabbitmq")]
535impl From<deadpool::managed::PoolError<lapin::Error>> for AppMessage {
536    fn from(value: deadpool::managed::PoolError<lapin::Error>) -> Self {
537        AppMessage::RmqPoolError(value)
538    }
539}
540
541#[cfg(feature = "hmac")]
542impl From<hmac::digest::InvalidLength> for AppMessage {
543    fn from(value: hmac::digest::InvalidLength) -> Self {
544        AppMessage::HmacError(value)
545    }
546}
547
548impl From<serde_json::Error> for AppMessage {
549    fn from(value: serde_json::Error) -> Self {
550        AppMessage::SerdeError(value)
551    }
552}
553
554impl From<chrono::ParseError> for AppMessage {
555    fn from(value: chrono::ParseError) -> Self {
556        AppMessage::ChronoParseError(value)
557    }
558}
559
560impl From<std::string::FromUtf8Error> for AppMessage {
561    fn from(value: std::string::FromUtf8Error) -> Self {
562        AppMessage::FromUtf8Error(value)
563    }
564}
565
566impl From<std::str::Utf8Error> for AppMessage {
567    fn from(value: std::str::Utf8Error) -> Self {
568        AppMessage::StrUtf8Error(value)
569    }
570}
571
572#[cfg(feature = "strum")]
573impl From<strum::ParseError> for AppMessage {
574    fn from(value: strum::ParseError) -> Self {
575        AppMessage::StrumParseError(value)
576    }
577}
578
579#[cfg(feature = "multipart")]
580impl From<medullah_multipart::MultipartError> for AppMessage {
581    fn from(value: medullah_multipart::MultipartError) -> Self {
582        AppMessage::MultipartError(value)
583    }
584}
585
586#[cfg(feature = "base64")]
587impl From<base64::DecodeError> for AppMessage {
588    fn from(value: base64::DecodeError) -> Self {
589        AppMessage::Base64Error(value)
590    }
591}
592
593#[cfg(feature = "database")]
594impl From<diesel::result::Error> for AppMessage {
595    fn from(value: diesel::result::Error) -> Self {
596        AppMessage::DatabaseError(value)
597    }
598}
599
600#[cfg(feature = "database")]
601impl From<AppMessage> for diesel::result::Error {
602    fn from(value: AppMessage) -> Self {
603        use diesel::result::Error as DieselError;
604
605        match value {
606            AppMessage::EntityNotFound(_) => diesel::result::Error::NotFound,
607            AppMessage::DatabaseError(DieselError::DatabaseError(
608                diesel::result::DatabaseErrorKind::UniqueViolation,
609                x,
610            )) => DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, x),
611            AppMessage::DatabaseError(err) => err,
612            _ => panic!("unhandled app message: {:?}", value),
613        }
614    }
615}
616
617impl AppMessage {
618    pub fn http_result(&self) -> crate::results::HttpResult {
619        Ok(self.http_response())
620    }
621
622    pub fn http_response(&self) -> ntex::web::HttpResponse {
623        send_response(self)
624    }
625
626    pub fn status_code(&self) -> StatusCode {
627        get_status_code(self)
628    }
629
630    pub fn message(&self) -> String {
631        get_message(self)
632    }
633}
634
635impl WebResponseError for AppMessage {
636    fn status_code(&self) -> StatusCode {
637        let code = self.status_code();
638        log::info!("[error-code] {}", code);
639        code
640    }
641
642    fn error_response(&self, _: &HttpRequest) -> ntex::web::HttpResponse {
643        log::info!("[error-body] {}", self);
644        self.http_response()
645    }
646}