Axum Error Handler
A simple parser that implemented Axum IntoResponse
trait.
Please notice that this is a experimental project.
This proc-macros depends on axum
, thiserror
and serde_json
crates.
Basic Usage
use axum_error_handler::AxumErrorResponse;
use thiserror::Error;
#[derive(Debug, Error, AxumErrorResponse)]
pub enum TestError {
#[error("Bad request: {0}")]
#[status_code("400")]
#[code("BAD_REQUEST")]
BadRequest(String),
#[error("Internal server error {0}")]
#[status_code("500")]
#[code("INTERNAL_SERVER_ERROR")]
InternalError(String),
}
Basic Output
{
"result": null,
"error": {
"code": "BAD_REQUEST",
"message": "Bad request: invalid input"
}
}
Nested Response Support
The library supports nested error handling through the #[response(nested)]
attribute. This allows inner errors that also implement AxumErrorResponse
to be properly forwarded with their own status codes and error details.
Example
use axum_error_handler::AxumErrorResponse;
use thiserror::Error;
#[derive(Debug, Error, AxumErrorResponse)]
pub enum AppError {
#[error("Bad request: {0}")]
#[status_code("400")]
#[code("BAD_REQUEST")]
BadRequest(String),
#[error("{0}")]
#[response(nested)]
ServiceError(#[from] ServiceError),
}
#[derive(Debug, Error, AxumErrorResponse)]
pub enum ServiceError {
#[error("Authentication error: {0}")]
#[status_code("401")]
#[code("AUTHENTICATION_ERROR")]
AuthenticationError(String),
#[error("Database connection failed: {0}")]
#[status_code("503")]
#[code("DATABASE_ERROR")]
DatabaseError(String),
#[error("{0}")]
#[response(nested)]
ValidationError(#[from] ValidationError),
}
#[derive(Debug, Error, AxumErrorResponse)]
pub enum ValidationError {
#[error("Validation failed: {0}")]
#[status_code("422")]
#[code("VALIDATION_ERROR")]
FieldValidation(String),
#[error("Permission denied: {0}")]
#[status_code("403")]
#[code("PERMISSION_DENIED")]
PermissionDenied(String),
}
Usage
let err = AppError::BadRequest("missing field".to_string());
let service_err = ServiceError::AuthenticationError("invalid token".to_string());
let app_err = AppError::ServiceError(service_err);
let validation_err = ValidationError::FieldValidation("email format invalid".to_string());
let service_err = ServiceError::ValidationError(validation_err);
let app_err = AppError::ServiceError(service_err);
Nested Response Output
When using nested responses, the inner error's status code, error code, and message are preserved:
{
"result": null,
"error": {
"code": "AUTHENTICATION_ERROR",
"message": "Authentication error: invalid token"
}
}
Key Features
- Status Code Preservation: Nested errors maintain their original HTTP status codes
- Error Code Forwarding: Custom error codes from inner errors are preserved
- Multiple Nesting Levels: Supports arbitrarily deep error nesting
- Automatic Conversion: Use
#[from]
attribute for automatic error conversion
- Consistent JSON Format: All responses follow the same
{"result": null, "error": {...}}
structure