| Crates.io | standard-error |
| lib.rs | standard-error |
| version | 0.1.10 |
| created_at | 2024-08-17 12:56:58.188819+00 |
| updated_at | 2025-06-07 02:52:26.227111+00 |
| description | simplifies returning meaningful errors for axum services |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1341626 |
| size | 140,884 |
standard-error is a Rust crate designed to simplify the handling of error messages for various locales. It reads error messages from YAML and other sources, providing a structured and efficient way to manage errors in your applications.
Axum.Below is an example of how to use standard-error in a web application using the Axum framework:
use axum::{
extract::Query,
Json,
http::StatusCode,
};
use serde_json::{json, Value};
use std::collections::HashMap;
use standard_error::StandardError;
pub async fn my_handler(Query(params): Query<HashMap<String, String>>) -> Result<Json<Value>, StandardError> {
let group = match params.get("name") {
Some(g) => g,
None => {
return Err(StandardError::new("ER-0037").code(StatusCode::BAD_REQUEST));
}
};
Ok(Json(json!({"message": "success"})))
}
If a parsing error occurs (e.g., trying to convert a string to an integer), a StandardError can be returned with a default status code (500 INTERNAL_SERVER_ERROR):
async fn parse_int(a: &str) -> Result<i32, StandardError> {
a.parse().map_err(|_| StandardError::new("ER-0004"))
}
// Example usage
let res = parse_int("abc").await;
// This will return an error with code "ER-0004" and status code 500.
You can customize the status code to something other than the default. For example, returning 400 BAD_REQUEST:
async fn parse_int_custom(a: &str) -> Result<i32, StandardError> {
a.parse().map_err(|_| StandardError::new("ER-0004").code(StatusCode::BAD_REQUEST))
}
// Example usage
let res = parse_int_custom("abc").await;
// This will return an error with code "ER-0004" and status code 400.
StandardError supports error message interpolation. For example, you can include the specific error details when returning the error:
async fn parse_with_error_interpolation(a: &str) -> Result<i32, StandardError> {
a.parse().map_err(|e| StandardError::new("ER-0005").interpolate_err(e.to_string()))
}
// Example usage
let res = parse_with_error_interpolation("abc").await;
// This will return an error with code "ER-0005" and message: "Should be an integer: invalid digit found in string".
You can interpolate additional values into the error message, such as user-specific data:
async fn parse_with_value_interpolation(a: &str) -> Result<i32, StandardError> {
a.parse().map_err(|_| {
let mut values = HashMap::new();
values.insert("fname".to_string(), "ashu".to_string());
values.insert("lname".to_string(), "pednekar".to_string());
StandardError::new("ER-0006").interpolate_values(values)
})
}
// Example usage
let res = parse_with_value_interpolation("abc").await;
// This will return an error with code "ER-0006" and message: "Should be an integer - fname: ashu | lname: pednekar".
You can chain multiple methods on StandardError, like setting a custom status code and interpolating both error details and values:
async fn parse_with_chained_errors(a: &str) -> Result<i32, StandardError> {
a.parse().map_err(|e| {
let mut values = HashMap::new();
values.insert("fname".to_string(), "ashu".to_string());
values.insert("lname".to_string(), "pednekar".to_string());
StandardError::new("ER-0007")
.code(StatusCode::IM_A_TEAPOT)
.interpolate_values(values)
.interpolate_err(e.to_string())
})
}
// Example usage
let res = parse_with_chained_errors("abc").await;
// This will return an error with code "ER-0007", status code 418, and message:
// "Should be an integer - fname: ashu | lname: pednekar - invalid digit found in string".
Make sure you have the askama feature enabled, then you can use the HtmlRes trait by calling .template and pass in the rendered template, here's an example auth middleware use case
note: this feature is only available in version
0.1.8onwards
use askama::Template;
use axum::{
extract::{Request, State},
http::{HeaderMap, StatusCode, header::COOKIE},
middleware::Next,
response::Response,
};
use axum_extra::extract::CookieJar;
use sqlx::query;
use standard_error::{HtmlRes, StandardError, Status};
use crate::prelude::Result;
#[derive(Template)]
#[template(path = "verify.html")]
pub struct Verify {}
pub async fn authenticate(
request: Request,
next: Next,
) -> Result<Response> {
match CookieJar::from_headers(&headers)
.get("_Host_lwsuser")
.filter(|c| !c.value().is_empty())
{
Some(token) => {
// verify and proceed
}
None => {
return Err(StandardError::new("ERR-AUTH-001")
.code(StatusCode::UNAUTHORIZED)
.template(Verify {}.render()?));
}
};
Ok(next.run(request).await)
}
Add standard-error to your Cargo.toml:
[dependencies]
standard-error = "0.1"
or with cargo
cargo add standard-error
Note: Add features
dieselorgitto auto-magically handle errors raised by these diesel and git2 crates respectively
To configure standard-error, you can provide YAML files containing error messages for different locales. The crate will automatically load the correct message based on the locale specified in your application.
Example YAML structure:
errors:
- code: ER-0004
detail_en_US: "Should be an integer"
detail_hi_IN: "एक पूर्णांक होना चाहिए"
- code: ER-0005
detail_en_US: "Should be an integer: [err]"
detail_hi_IN: "एक पूर्णांक होना चाहिए: [err]"
- code: ER-0006
detail_en_US: "Should be an integer - fname: [fname] | lname: [lname]"
detail_hi_IN: "एक पूर्णांक होना चाहिए - fname: [fname] | lname: [lname]"
- code: ER-0007
detail_en_US: "Should be an integer - fname: [fname] | lname: [lname] - [err]"
detail_hi_IN: "एक पूर्णांक होना चाहिए - fname: [fname] | lname: [lname] - [err]"
Keep this yaml file (
errors.yaml) at the root of your directory, outsidesrc. Or you can keep it wherever you please and set theERROR_YAML_FILE_PATHenvironment variable.
As for the locale configuration, by default, the crate picks up the default value from the
DEFAULT_LOCALEenv, which is set toen_USby default.
- You can change this env to any value you like, provided the corresponding keys are present in yout errors yaml file.
If you wish to dynamically change the locale programmatically at any given point, you can call the
standard_error::set_current_localefunction like so
use standard_error::set_current_locale;
fn my_business_logic(){
//...
set_current_locale("hi_IN");
//...
}
This sets a thread local refcell variable that'll persist throught the thread. Since it's a
RefCellvalue, and not something likeArc, you don't have to worry about it leaking into your other threads/requests.