use rocket::{ http::{ContentType, Status}, request::Request, response::{self, Responder, Response}, }; use rocket_okapi::okapi::openapi3::Responses; use rocket_okapi::okapi::schemars::{self, Map}; use rocket_okapi::{gen::OpenApiGenerator, response::OpenApiResponderInner, OpenApiError}; /// Error messages returned to user #[derive(Debug, serde::Serialize, schemars::JsonSchema)] pub struct Error { /// The title of the error message pub err: String, /// The description of the error pub msg: Option, // HTTP Status Code returned #[serde(skip)] pub http_status_code: u16, } impl OpenApiResponderInner for Error { fn responses(_generator: &mut OpenApiGenerator) -> Result { use rocket_okapi::okapi::openapi3::{RefOr, Response as OpenApiReponse}; let mut responses = Map::new(); responses.insert( "400".to_string(), RefOr::Object(OpenApiReponse { description: "\ # [400 Bad Request](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400)\n\ The request given is wrongly formatted or data asked could not be fulfilled. \ " .to_string(), ..Default::default() }), ); responses.insert( "404".to_string(), RefOr::Object(OpenApiReponse { description: "\ # [404 Not Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404)\n\ This response is given when you request a page that does not exists.\ " .to_string(), ..Default::default() }), ); responses.insert( "422".to_string(), RefOr::Object(OpenApiReponse { description: "\ # [422 Unprocessable Entity](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422)\n\ This response is given when you request body is not correctly formatted. \ ".to_string(), ..Default::default() }), ); responses.insert( "500".to_string(), RefOr::Object(OpenApiReponse { description: "\ # [500 Internal Server Error](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500)\n\ This response is given when something wend wrong on the server. \ ".to_string(), ..Default::default() }), ); Ok(Responses { responses, ..Default::default() }) } } impl std::fmt::Display for Error { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( formatter, "Error `{}`: {}", self.err, self.msg.as_deref().unwrap_or("") ) } } impl std::error::Error for Error {} impl<'r> Responder<'r, 'static> for Error { fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { // Convert object to json let body = serde_json::to_string(&self).unwrap(); Response::build() .sized_body(body.len(), std::io::Cursor::new(body)) .header(ContentType::JSON) .status(Status::new(self.http_status_code)) .ok() } } impl From> for Error { fn from(err: rocket::serde::json::Error) -> Self { use rocket::serde::json::Error::*; match err { Io(io_error) => Error { err: "IO Error".to_owned(), msg: Some(io_error.to_string()), http_status_code: 422, }, Parse(_raw_data, parse_error) => Error { err: "Parse Error".to_owned(), msg: Some(parse_error.to_string()), http_status_code: 422, }, } } }