| Crates.io | actix_failwrap |
| lib.rs | actix_failwrap |
| version | 1.0.3 |
| created_at | 2025-08-24 00:16:31.175197+00 |
| updated_at | 2025-09-24 12:26:09.720857+00 |
| description | A micro-package that enables ergonomic error propagation (using thiserror) inside actix-web route handlers. |
| homepage | |
| repository | https://github.com/FlakySL/actix_failwrap |
| max_upload_size | |
| id | 1807972 |
| size | 195,183 |
actix_failwrap /ˈæk.tɪks ˈfeɪl.ræp/ ("aktiks fail-rap") A micro-package that enables ergonomic error propagation (via thiserror) inside Actix Web route handlers.
This crate allows you to:
thiserror enums.? operator naturally inside route handlers.✅ Automatic error-to-response conversion using thiserror enums
Define route errors with #[derive(ErrorResponse)] to auto-generate HttpResponse.
🧩 Custom response transformation per error enum
Use #[transform_response(fn)] to modify headers, body, or status codes.
🧠 Per-variant status code overrides
Set status codes using #[status_code(...)] — supports both constants and numbers.
🔁 Fallback behavior for unannotated variants
Variants without #[status_code] fall back to #[default_status_code] or HTTP 500.
✍️ Extractor error mapping with #[error_override(...)]
Map deserialization or extractor failures to your own enum variant.
⚡ Minimal boilerplate route macros with #[proof_route(...)]
Use ? with error enums directly and skip actix_web macro imports.
[!IMPORTANT] The
actix_failwrapmacros rely onthiserrorfor theDisplayimplementation, and are tightly coupled withactix-webfor building HTTP responses.
This crate is published on crates.io
and is intended for use alongside actix-web
and thiserror.
Add all three to your Cargo.toml:
[dependencies]
actix-web = "4"
thiserror = "1"
actix_failwrap = "1.0.0"
This example shows a login route in Actix Web using actix_failwrap.
In your project you may have a module that declares models, in this case a User model.
In that file you may declare your thiserror error that you may re-use for your handler.
use serde::{Serialize, Deserialize};
use actix_failwrap::ErrorResponse;
use thiserror::Error;
// Custom error transformation function used by #[transform_response]
// Converts an error into a response with an "Error" header.
fn error_to_header(mut response: HttpResponseBuilder, error: String) -> HttpResponse {
response.insert_header(("Error", error)).finish()
}
// Define a custom error enum for user-related errors.
#[derive(ErrorResponse, Error, Debug)]
// Default fallback for variants without #[status_code],
// if the attribute is not present, the default status code will be 500.
#[default_status_code(InternalServerError)]
// Function used to transform the final HttpResponse,
// if the attribute not present, the Display is mapped to the body.
#[transform_response(error_to_header)]
pub enum UserError {
#[error("Either the email or the password is invalid. Please check the input credentials")]
// This can also be a numeric HTTP status code.
#[status_code(Unauthorized)]
InvalidCredentials,
#[error("Missing credentials, please, introduce your email and password.")]
#[status_code(BadRequest)]
MissingCredentials,
}
#[derive(Serialize, Deserialize)]
pub struct UserCredentials {
pub email: String,
pub password: String,
}
// Simulates a function that attempts to authenticate a user and returns a Result
pub fn obtain_user(credentials: UserCredentials) -> Result<User, UserError> {
/* ... */
}
And another module that declares handlers, this example handler obtains a user with some credentials and returns its JWT token if successful.
use actix_failwrap::proof_route;
use actix_web::{web::Form, HttpResponse, HttpResponseBuilder};
use crate::models::user::{UserError, UserCredentials, obtain_user};
// Route macro expands to #[actix_web::post("/login")] and allows
// to use `Result<HttpResponse, _>`.
#[proof_route("POST /login")]
async fn post_login(
// If the extractor (Form) fails, override it with MissingCredentials variant
#[error_override(MissingCredentials)] credentials: Form<UserCredentials>
) -> Result<HttpResponse, UserError> {
// Attempt to obtain the user; if it fails, propagate the error
let user = obtain_user(credentials.into_inner())?;
// On success, return a response with a "Login" header containing the JWT
Ok(
HttpResponse::Ok().
.insert_header(("Login", user.jwt()))
.finish()
)
}
This crate exports two macros: ErrorResponse and proof_route.
#[derive(ErrorResponse)]Implements Into<actix_web::HttpResponse> and Into<actix_web::Error> for your thiserror enums,
allowing direct propagation with the ? operator in handlers.
[!WARNING] Requires
#[derive(thiserror::Error)]because it uses theDisplayimplementation.
#[default_status_code(...)]
Fallback status code used if a variant does not have its own #[status_code(...)]
Defaults to InternalServerError (500).
#[status_code(...)]
Sets the HTTP status code for a specific variant. Accepts a named status (e.g. BadRequest) or number (400).
#[transform_response(fn)]
Customizes how the response is built. Takes a function of signature:
fn(HttpResponseBuilder, String) -> HttpResponse.
#[proof_route(...)]Simplifies route definition and error propagation.
#[proof_route("POST /path")]
Expands to:
#[actix_web::post("/path")]
An example function signature looks like
#[proof_route("GET /users")]
async fn get_users() -> Result<HttpResponse, Error> {}
[!TIP] You can use a
Result<T: actix_web::Responder, Error>instead ofHttpResponse.
Allows you to:
Result<HttpResponse, Error> directly in route bodies.#[post], #[get], etc. individually.#[error_override(...)].Security is a top priority for us. If you believe you’ve found a security vulnerability, do not open a public issue. Instead, please read our SECURITY.md policy and report it responsibly by contacting us at security@flaky.es.
This repository is dual licensed, If your repository is open source, the library is free of use, otherwise contact licensing@flaky.es for a custom license for your use case.
For more information read the license file.