2 releases (1 stable)
1.0.0 | Apr 5, 2023 |
---|---|
0.1.0 | Apr 5, 2023 |
#1430 in HTTP server
24 downloads per month
17KB
310 lines
Error handling helpers for axum
while using anyhow
,
focusing on how to safely unwrap Result<T, E>
and Option<T>
in an ergonomic way.
Usage
There are two recommended approaches to implementing recoil
for error handling in your axum
server application.
Both approaches take advantage of the fact that,
because recoil::Failure
(and anything that implements recoil::ErrorResponder
) generates a type that implements axum::response::IntoResponse
,
you can call .into_response
and return it as a http::response::Response
to axum
.
If-Let-Err Pattern
For each fallible handler, return Response
.
When encountering a Result
or an Option
, use if let
to handle the error branch,
and then Failure
(or anything that implements ErrorResponder
),
to manually generate a response for the error.
use std::fs::write;
use recoil::{ErrorResponder, Failure};
use axum::{
response::{IntoResponse, Response},
http::StatusCode
};
fn your_handler() -> Response {
if let Err(error) = write("/root/warning.txt", "Big brother is watching you.") {
return Failure::fail_because("Failed to write to path /root/warning.txt on file system.", error.into(), None).into_response();
}
// the ok branch continues until the end of the handler.
(StatusCode::CREATED, "Handled successfully.").into_response()
}
// ...rest of your server application code that integrates `your_handler()`.
This pattern however, is basic, and creates a lot of boilerplate code for catching error branches. Although a good starting point, you should use the more efficient "catch-method pattern," when handling errors in bulk.
Catch-Method Pattern
For each fallible handler, return Result<impl IntoResponse, Response>
.
When encountering a Result
or an Option
, use .recoil()
to handle the error branch,
with the trait recoil::Recoil
in scope, followed by the ?
operator,
to automatically generate a response for the error.
use std::fs::write;
use recoil::{Failure, Recoil};
use axum::{
response::{IntoResponse, Response},
http::StatusCode
};
fn your_handler() -> Result<impl IntoResponse, Response> {
write("/root/warning.txt", "Big brother is watching you.")
.recoil::<Failure>(Some("Failed to write to path /root/warning.txt on file system."), None)?;
// the ok branch continues until the end of the handler.
Ok((StatusCode::CREATED, "Handled successfully."))
}
// ...rest of your server application code that integrates `your_handler()`.
Customization
If the included error response structure does not fit your needs, you can write your own,
as long as it implements the required traits and methods for ErrorResponder
.
Feel free to make use of recoil::trace_error()
to produce error message sequences for your structure.
Custom responders can be used with Recoil::recoil
by specifying the responder as the generic,
in place of the included Failure
structure.
Headers
recoil
deliberately excludes the means to customize headers of error responses, for simplicity's sake.
Consider the following instead, if you want custom headers:
- Add middleware in your application to inject headers.
- Don't use this library and write your own implementation.
http::response::Response
(which is the structure produced by IntoResponse
) has the method .headers_mut()
,
which returns a mutable reference to the response's internal HeaderMap
, and is where you can inject your headers.
Dependencies
~6–13MB
~145K SLoC