rocketjson_data/error/
error_handling.rs

1//!# Handeling errors
2//!Use [`get_catcher`] to transform errors into Json.
3
4use crate::error::{self, JsonBodyError};
5
6///Transforms errors into Json
7///# Example
8///```
9///#[launch]
10///fn rocket() -> _ {
11///    rocket::build()
12///        .mount("/", routes![]).
13///        register("/", vec![rocketjson::error::get_catcher()])
14///}
15///```
16pub fn get_catcher() -> rocket::Catcher {
17    rocket::Catcher::new(None, request_catcher)
18}
19
20#[derive(serde::Serialize)]
21struct DefaultError {
22    error: String
23}
24
25impl DefaultError {
26    fn new(error: String) -> Self {
27        Self {
28            error
29        }
30    }
31}
32
33fn request_catcher<'r>(status: rocket::http::Status, req: &'r rocket::Request<'_>) -> rocket::catcher::BoxFuture<'r> {
34    use rocket::response::Responder;
35
36    loop {
37        let local_cache = req.local_cache(move || JsonBodyError::NoError);
38
39        match local_cache {
40            JsonBodyError::NoError => break,
41            JsonBodyError::ValidationError(validation_errors) => {
42                let err = rocket::serde::json::Json::from(validation_errors.clone());
43                return Box::pin(async move {
44                    rocket::response::Response::build_from(err.respond_to(req).unwrap())
45                    .status(rocket::http::Status::BadRequest)
46                    .header(rocket::http::ContentType::JSON)
47                    .ok()
48                });
49            },
50            JsonBodyError::JsonValidationError => {
51                let err = rocket::serde::json::Json::from(DefaultError::new(String::from("Parsing JSON failed")));
52
53                return Box::pin(async move {
54                    rocket::response::Response::build_from(err.respond_to(req).unwrap())
55                    .status(status)
56                    .header(rocket::http::ContentType::JSON)
57                    .ok()
58                })
59            },
60            JsonBodyError::CustomError(message) => {
61                let err = rocket::serde::json::Json::from(DefaultError::new(message.clone()));
62
63                return Box::pin(async move {
64                    rocket::response::Response::build_from(err.respond_to(req).unwrap())
65                    .status(status)
66                    .header(rocket::http::ContentType::JSON)
67                    .ok()
68                })
69            }
70        }
71    }
72
73    let message = if status.reason().is_some() {
74        String::from(status.reason().unwrap())
75    } else {
76        format!("Unknown error: {}", status.code)
77    };
78
79    let err = rocket::serde::json::Json::from(DefaultError::new(message));
80
81    return Box::pin(async move {
82        rocket::response::Response::build_from(err.respond_to(req).unwrap())
83        .status(status)
84        .header(rocket::http::ContentType::JSON)
85        .ok()
86    })
87}
88
89impl<'r> rocket::response::Responder<'r, 'static> for error::ApiErrors {
90    fn respond_to(self, req: &'r rocket::request::Request<'_>) -> rocket::response::Result<'static> {
91        match self {
92            error::ApiErrors::ApiError(err) => {
93                let json = rocket::serde::json::Json::from(DefaultError::new(err.error));
94
95                rocket::response::Response::build_from(json.respond_to(req).unwrap())
96                    .status(err.status)
97                    .header(rocket::http::ContentType::JSON)
98                    .ok()
99            },
100            error::ApiErrors::AnyError(_) => {
101                let json = rocket::serde::json::Json::from(DefaultError::new(String::from("Internal server error")));
102
103                rocket::response::Response::build_from(json.respond_to(req).unwrap())
104                    .status(rocket::http::Status::InternalServerError)
105                    .header(rocket::http::ContentType::JSON)
106                    .ok()
107            }
108        }
109    }
110}