Crate axum_dyn_error

Source
Expand description

§Axum-dyn-error

Dynamic error handling for Axum HTTP handlers

[dependencies]
axum-dyn-error = "0.1"

Only supports axum v0.6

This crate provides foundational logic for creating and handling dynamic HTTP errors.

Implementing the HttpError trait on errors allows you to customize how the errors and displayed in error responses.

I recommend using thiserror for defining your user facing error types.

In order to use the dynamic error handling you should replace your Result return types with the HttpResult type from axum_dyn_error.


use axum_dyn_error::{HttpResult, HttpError, StatusCode};
use thiserror::Error;
use axum::{extract::Path, Json};

#[derive(Debug, Error)]
pub enum ExampleError {
    #[error("User not found")]
    MissingUser,
    #[error("Username was invalid")]
    InvalidUsername
}

impl HttpError for ExampleError {

    /// Customize the HTTP status code
    fn status(&self) -> StatusCode {
        match self {
            ExampleError::MissingUser => StatusCode::NOT_FOUND,
            ExampleError::InvalidUsername => StatusCode::BAD_REQUEST
        }
    }
}

/// Dummy structure representing a user
pub struct User;

/// Mock function for finding a user by id
pub async fn get_user_by_id(user_id: u32) -> Option<User> { unimplemented!() }

/// Example handler
pub async fn example_handler(
    Path(user_id): Path<u32>
) -> HttpResult<Json<User>> {
    let user = get_user_by_id(user_id)
        .await
        .ok_or(ExampleError::MissingUser)?;

    Ok(Json(user))
}

§Anyhow support

Axum-dyn-error supports anyhow errors through the anyhow feature flag, by default the hide-anyhow feature flag is enabled which prevents the anyhow error message from being included in the error response instead responding with “Server error”.


use axum_dyn_error::{HttpResult, HttpError, StatusCode};
use axum::{extract::Path, Json};
use anyhow::anyhow;

/// Dummy structure representing a user
pub struct User;

/// Mock function for finding a user by id
pub async fn get_user_by_id(user_id: u32) -> Option<User> { unimplemented!() }

/// Example handler
pub async fn example_handler(
    Path(user_id): Path<u32>
) -> HttpResult<Json<User>> {
    let user = get_user_by_id(user_id)
        .await
        .ok_or(anyhow!("Missing user"))?;

    Ok(Json(user))
}

Using AnyhowStatusExt the anyhow error types can have an HTTP status code associated with them, by default anyhow errors just use “500 Internal server error”:


use axum_dyn_error::{HttpResult, HttpError, StatusCode, anyhow::AnyhowStatusExt};
use axum::{extract::Path, Json};
use anyhow::anyhow;

/// Dummy structure representing a user
pub struct User;

/// Mock function for finding a user by id
pub async fn get_user_by_id(user_id: u32) -> Option<User> { unimplemented!() }

/// Example handler
pub async fn example_handler(
    Path(user_id): Path<u32>
) -> HttpResult<Json<User>> {
    let user = get_user_by_id(user_id)
        .await
        .ok_or(
            anyhow!("Missing user")
                .status(StatusCode::NOT_FOUND)
        )?;

    Ok(Json(user))
}

§Custom response

By default the responses generated from the errors use the “reason” as a text response body. You can change this by create a structure and implementing IntoHttpErrorResponse on that structure:


use axum_dyn_error::{HttpResult, HttpError, IntoHttpErrorResponse};
use axum::response::{Response, IntoResponse};

pub struct CustomErrorResponse;

impl IntoHttpErrorResponse for CustomErrorResponse {
    fn into_response(error: Box<dyn HttpError>) -> Response {
        // Your logic to create the response from the error example:
        (error.status(), error.reason()).into_response()
    }
}

// You can then alias the HttpResult type
pub type MyHttpResult<T> = HttpResult<T, CustomErrorResponse>;

§Crate Features

The default features are ["log", "hide-anyhow"]

FeatureDescription
logLogs errors that are created using log::error!
anyhowAdds support for handling anyhow error types
hide-anyhowReplaces anyhow error messages in HTTP responses with a generic server error message

Re-exports§

pub use anyhow::*;

Modules§

anyhow
Wrappers and extension traits for anyhow support

Structs§

DynHttpError
Structure that stores dynamic error responses, see documentation home page for usage
GenericServerError
Wrapper around an error type that displays a generic error message and server status
StatusCode
An HTTP status code (status-code in RFC 7230 et al.).
TextErrorResponse
Creates HTTP errors responses where the “reason” is provided as the text contents of the response and the status is used as the HTTP status

Traits§

ErrorExt
Extension trait for the Error trait for extra functionality
HttpError
This trait should be implemented by error types that can be used as HTTP error responses
IntoHttpErrorResponse
Trait for implementing different response converter implementations the default is TextErrorResponse

Type Aliases§

HttpResult
Alias for Result that has a DynHttpError as the error type