Trait Error

Source
pub trait Error:
    Debug
    + Send
    + Typeable
    + Error { }
Expand description

An extension to std::error::Error which provides dynamic downcasting of errors for use in highly generic contexts.

§When to use this trait

In the vast majority of cases, a library-specific enum should be used for cases where there can be many different types of errors. This has the benefit of being very performant and benefiting from all sorts of static checking at both the instantiation site and the handling site of the error.

In other cases, being generic over std::error::Error may be correct

  • usually for logging errors or in other places where an error is used as input.

Now, a motivating example for this trait, which doesn’t fall under either of these cases:

Imagine we are creating a simple web middleware for verifying incoming HTTP requests. It will take in many different user-defined Verifiers and will call them one after the other, rejecting the request on any error.

The first step would be to write a Verifier trait:

pub trait Verifier {
    /// Verify the request, yielding an error if the request is invalid.
    fn verify(&Request) -> Result<(), ???>;
}

A problem quickly arises - what type do we use for the Err case? We cannot use a concrete type since each Verifier may wish to throw any number of different errors, and we cannot use a generic since the type is chosen by the implementor, not the caller, and it cannot be a generic on the trait since we will want to store many Verifiers together.

Enter: Box<error::Error>, a type which can be used to represent any std::error::Error with the sufficient bounds, and can also be handled later by downcasting it to the right error using either .downcast or the match_error! macro. This type can be used to meet the needs of consumers like Verifier, but should not be used in cases where enums or generics are better suited.

Implementations§

Source§

impl dyn Error

Source

pub fn is<E>(&self) -> bool
where E: Error,

Is this Error object of type E?

Source

pub fn downcast<E>(&self) -> Option<&E>
where E: Error,

If this error is E, downcast this error to E, by reference.

Examples found in repository?
examples/simple.rs (line 45)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
fn main() {

    let mut app = rustless::Application::new(rustless::Api::build(|api| {
        api.prefix("api");
        api.version("v1", rustless::Versioning::Path);

        api.mount(swagger::create_api("api-docs"));

        api.error_formatter(|err, _media| {
            match err.downcast::<UnauthorizedError>() {
                Some(_) => {
                    return Some(rustless::Response::from(
                        status::StatusCode::Unauthorized,
                        Box::new("Please provide correct `token` parameter")
                    ))
                },
                None => None
            }
        });

        api.post("greet/:name", |endpoint| {
            endpoint.summary("Sends greeting");
            endpoint.desc("Use this to talk to yourself");
            endpoint.params(|params| {
                params.req_typed("name", json_dsl::string());
                params.req_typed("greeting", json_dsl::string());
            });
            endpoint.handle(|client, params| {
                client.text(
                    format!("{}, {}",
                        params.find("greeting").unwrap().to_string(),
                        params.find("name").unwrap().to_string())
                )
            })
        });

        api.get("echo", |endpoint| {
            endpoint.summary("Sends back what it gets");
            endpoint.desc("Use this to talk to yourself");
            endpoint.handle(|client, params| {
                client.json(params)
            })
        });

        api.namespace("admin", |admin_ns| {

            admin_ns.params(|params| {
                params.req_typed("token", json_dsl::string())
            });

            // Using after_validation callback to check token
            admin_ns.after_validation(|_client, params| {

                match params.find("token") {
                    // We can unwrap() safely because token in validated already
                    Some(token) => if token.as_str().unwrap() == "password1" { return Ok(()) },
                    None => ()
                }

                // Fire error from callback is token is wrong
                return Err(rustless::ErrorResponse{
                    error: Box::new(UnauthorizedError) as Box<Error + Send>,
                    response: None
                })

            });

            // This `/api/admin/server_status` endpoint is secure now
            admin_ns.get("server_status", |endpoint| {
                endpoint.summary("Get server status");
                endpoint.desc("Use this API to receive some useful information about the state of our server");
                endpoint.handle(|client, _params| {
                    {
                        let cookies = client.request.cookies();

                        #[cfg(feature = "ssl")]
                        let signed_cookies = cookies.signed();
                        #[cfg(not(feature = "ssl"))]
                        let signed_cookies = cookies;

                        let user_cookie = Cookie::new("session".to_string(), "verified".to_string());
                        signed_cookies.add(user_cookie);
                    }

                    client.text("Everything is OK".to_string())
                })
            });
        })
    }));

    swagger::enable(&mut app, swagger::Spec {
        info: swagger::Info {
            title: "Example API".to_string(),
            description: Some("Simple API to demonstration".to_string()),
            contact: Some(swagger::Contact {
                name: "Stanislav Panferov".to_string(),
                url: Some("http://panferov.me".to_string()),
                ..std::default::Default::default()
            }),
            license: Some(swagger::License {
                name: "MIT".to_string(),
                url: "http://opensource.org/licenses/MIT".to_string()
            }),
            ..std::default::Default::default()
        },
        ..std::default::Default::default()
    });

    let mut chain = iron::Chain::new(app);
    chain.link(::rustless::batteries::cookie::new("secretsecretsecretsecretsecretsecretsecret".as_bytes()));

    iron::Iron::new(chain).http("0.0.0.0:4000").unwrap();
    println!("On 4000");

}
Source§

impl dyn Error + Send

Source

pub fn is<E>(&self) -> bool
where E: Error + Send,

Is this Error + Send object of type E?

Source

pub fn downcast<E>(&self) -> Option<&E>
where E: Error + Send,

If this error is E, downcast this error to E, by reference.

Trait Implementations§

Source§

impl<E> From<E> for Box<dyn Error>
where E: Error,

Source§

fn from(e: E) -> Box<dyn Error>

Converts to this type from the input type.

Implementors§

Source§

impl<S> Error for S
where S: Error + Debug + Send + Typeable,