After playing around with rocket, I've found myself writing code like the following (this is just an example to show what I mean):
#[get("/")]
fn get() -> Result<status::Custom<JSON<Structure>>, Error> {
if 1 == 1 {
let structure = get_a_structure();
Ok(status::Custom(Status::Ok, JSON(structure)))
} else if 1 == 2 {
Err(Error::NotFound)
} else if 1 == 3 {
Err(Error::Unauthorized)
}
}
Where depending on different scenarios, I'm either returning a Ok or Err where the error could be a number of enum variants.
Without any error handlers set up in rocket, both errors just responds with a 500, but I'm imagining that one could set a handler up like:
#[error(_)]
fn not_found(e: Error) -> JSON<Error> {
// return appropriate json depending on what e is
}
That is, mounting an error handler that will catch all errors that are not handled by say a #[error(404)] handler, which can then act upon the Error that were returned by the route and give a proper response.
It doesn't seem like this is possible yet. I also don't know if there is an even better way to approach this problem, so my question is:
Err is returned from a route, since it doesn't seem like the error is available to the error handler.@ChrisBuchholz I believe this can be accomplished by creating your own Error type and implementing Responder for it: https://rocket.rs/guide/responses/#errors
@cbrewster: Ah, cool, do you know of any example of implementing Responder on an Error type?
Here is an example for when I was messing with Diesel:
use diesel::result::Error as DieselError;
use rocket::http::Status;
use rocket::response::{Response, Responder};
use rocket_contrib::JSON;
use std::error::Error;
#[derive(Debug)]
pub enum ApiError {
DieselError(DieselError)
}
#[derive(Serialize)]
pub struct ErrorResponse {
pub status: &'static str,
pub message: String,
}
pub type ApiResult<T> = Result<JSON<T>, ApiError>;
impl<'r> Responder<'r> for ApiError {
fn respond(self) -> Result<Response<'r>, Status> {
let message = match self {
ApiError::DieselError(error) => {
if error == DieselError::NotFound {
return Err(Status::NotFound);
}
String::from(error.description())
}
};
JSON(ErrorResponse {
status: "error",
message: message,
}).respond()
}
}
impl From<DieselError> for ApiError {
fn from(error: DieselError) -> ApiError {
ApiError::DieselError(error)
}
}
In my endpoint function I could do a try! on something that returned a Result that had an error type of diesel::result::Error which would then get converted to my ApiError using From<DieselError> for ApiError. If the endpoint returns an ApiError then my custom Responder impl is used for ApiError.
P.S: I thought this was a serious case of dejavu for a second there.
@SergioBenitez: Ha, my bad 馃槆
Most helpful comment
Here is an example for when I was messing with Diesel:
In my endpoint function I could do a
try!on something that returned aResultthat had an error type ofdiesel::result::Errorwhich would then get converted to myApiErrorusingFrom<DieselError> for ApiError. If the endpoint returns anApiErrorthen my customResponderimpl is used forApiError.