Crates.io | axum-route-error |
lib.rs | axum-route-error |
version | 5.0.1 |
source | src |
created_at | 2023-06-30 12:17:53.59464 |
updated_at | 2023-12-29 13:44:27.948638 |
description | A common error response for Axum servers |
homepage | |
repository | https://github.com/JosephLenton/axum-route-error |
max_upload_size | |
id | 904426 |
size | 19,090 |
This exists to encapsulate a number of common patterns when returning errors from Axum routes. These patterns include:
Below is a mock example route to download a User object:
use ::axum::extract::State;
use ::axum_route_error::RouteError;
use ::sea_orm::DatabaseConnection;
pub async fn route_get_user(
State(ref db): State<DatabaseConnection>,
Path(username): Path<String>
) -> Result<ExampleUser, RouteError> {
// If this errors, then a `RouteError::new_internal_server()` is returned.
let user = get_user_from_database(db, &username).await?;
Ok(user)
}
If the get_user_from_database
function returns an error,
then the handler will return a Response.
The Response will have a 500 status code (for an internal error),
and return the following output:
{
"error": "An unexpected error occurred"
}
RouteError
typesLet's presume get_user_from_database
returns a Result<Option, Error>
.
We want to return a 500 if it returns an error (like above),
and change the code to return a 404 if the user is not found.
use ::axum::extract::State;
use ::axum_route_error::RouteError;
use ::sea_orm::DatabaseConnection;
pub async fn route_get_user(
State(ref db): State<DatabaseConnection>,
Path(username): Path<String>
) -> Result<ExampleUser, RouteError> {
let user = get_user_from_database(db, &username).await?
// This additional line will return a 404 if the user is not found.
.ok_or_else(|| RouteError::new_not_found())?;
Ok(user)
}
If the user is not found (get_user_from_database
returns None
),
then this will return a 404 Response with the following JSON:
{
"error": "The resource was not found"
}
Next let's add extra information to the error. Something more than just an error message.
This can be done by making a new type that serializes using Serde,
and then adding this to the RouteError
.
use ::axum::extract::State;
use ::axum_route_error::RouteError;
use ::sea_orm::DatabaseConnection;
use ::serde::Deserialize;
use ::serde::Serialize;
// The additional error information needs to derive these three traits.
#[derive(Deserialize, Serialize, Debug)]
pub struct UserErrorInformation {
pub username: String
}
pub async fn route_get_user(
State(ref db): State<DatabaseConnection>,
Path(username): Path<String>
// The `RouteError` needs the additional data marked here
) -> Result<ExampleUser, RouteError<UserErrorInformation>> {
let user = get_user_from_database(db, &username).await?
.ok_or_else(move || {
// Then you can add the data through method chaining
RouteError::new_not_found()
.set_error_data(UserErrorInformation {
username,
})
})?;
Ok(user)
}
If the user is not found (get_user_from_database
returns None
),
then this will return a 404 Response with the following JSON:
{
"error": "The resource was not found",
"username": "<the-username>"
}
Sometimes you want to make internal errors public, such as for internal services.
For this you can use the RouteInternalError
. It's identical,
but adds adds internal_error
information to the response.