Error handling helpers for `axum` while using `anyhow`, focusing on how to safely unwrap `Result` and `Option` 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. ```rust 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`. 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. ```rust use std::fs::write; use recoil::{Failure, Recoil}; use axum::{ response::{IntoResponse, Response}, http::StatusCode }; fn your_handler() -> Result { write("/root/warning.txt", "Big brother is watching you.") .recoil::(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.