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
102
103
104
105
106
107
108
109
110
111
112
113
use rocket::http::Status;
use rocket::request::Request;
use rocket::response::{Responder, Response};

/// A specialized [`Status`](`rocket::http::Status`) struct that responds json errors.
///
/// This struct implements a [`Responder`](`rocket::response::Responder`) that will return json.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate rocket_contrib;
/// # fn main() {
/// use rocket_contrib::json::JsonValue;
/// use rocket_json::{Error, Result};
///
/// fn example(error: bool) -> Result<JsonValue> {
///     if error {
///         // Rocket will return status code 503:
///         // { "reason": "Service Unavailable", "status": 503 }
///         return Err(Error::ServiceUnavailable);
///     }
///     // Rocket will return status code 200:
///     // { "example": 42 }
///     Ok(json!({ "example": 42 }))
/// }
/// # }
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct Error(pub Status);

macro_rules! ctrs {
    ($($name:ident),+) => {
        $(
            #[allow(non_upper_case_globals)]
            pub const $name: Error = Error(Status::$name);
         )+
    }
}

impl Error {
    ctrs! {
        BadRequest,
        Unauthorized,
        PaymentRequired,
        Forbidden,
        NotFound,
        MethodNotAllowed,
        NotAcceptable,
        ProxyAuthenticationRequired,
        RequestTimeout,
        Conflict,
        Gone,
        LengthRequired,
        PreconditionFailed,
        PayloadTooLarge,
        UriTooLong,
        UnsupportedMediaType,
        RangeNotSatisfiable,
        ExpectationFailed,
        ImATeapot,
        MisdirectedRequest,
        UnprocessableEntity,
        Locked,
        FailedDependency,
        UpgradeRequired,
        PreconditionRequired,
        TooManyRequests,
        RequestHeaderFieldsTooLarge,
        UnavailableForLegalReasons,
        InternalServerError,
        NotImplemented,
        BadGateway,
        ServiceUnavailable,
        GatewayTimeout,
        HttpVersionNotSupported,
        VariantAlsoNegotiates,
        InsufficientStorage,
        LoopDetected,
        NotExtended,
        NetworkAuthenticationRequired
    }
}

impl From<Status> for Error {
    fn from(status: Status) -> Self {
        Error(status)
    }
}

impl AsRef<Status> for Error {
    fn as_ref(&self) -> &Status {
        &self.0
    }
}

impl AsMut<Status> for Error {
    fn as_mut(&mut self) -> &mut Status {
        &mut self.0
    }
}

impl<'r> Responder<'r> for Error {
    fn respond_to(self, req: &Request) -> Result<Response<'r>, Status> {
        let error = json!({
            "status": self.0.code,
            "reason": self.0.reason
        });

        Response::build_from(error.respond_to(req)?)
            .status(self.0)
            .ok()
    }
}