Crate bizerror

Source
Expand description

Β§BizError - Structured Business Error Handling for Rust

A lightweight, flexible business error handling library that provides structured error codes and contextual information while maintaining full compatibility with Rust’s error ecosystem.

§🎯 Design Philosophy

90/10 Principle: 90% of error handling scenarios only need error codes, while 10% require detailed context information.

  • Minimal Core: BizError trait contains only essential business error identification
  • Optional Context: Use ContextualError wrapper only when detailed context is needed
  • Zero Overhead: Basic usage scenarios have no additional performance cost
  • Full Compatibility: Seamlessly integrates with thiserror and the entire Rust error ecosystem

Β§πŸš€ Basic Usage with Derive Macro

The simplest way to use BizError is with the derive macro:

use bizerror::BizError;

#[derive(BizError, thiserror::Error)]
pub enum ApiError {
    #[bizcode(4001)]
    #[error("Invalid input: {field}")]
    ValidationError { field: String },

    #[bizcode(8001)]
    #[error("Database connection failed")]
    DatabaseError(#[from] std::io::Error),

    #[bizcode(8006)]
    #[error("Request timeout")]
    Timeout,
}

// Use the error
let error = ApiError::ValidationError { field: "email".to_string() };
assert_eq!(error.code(), 4001);
assert_eq!(error.name(), "ValidationError");
assert_eq!(error.to_string(), "Invalid input: email"); // Uses Display implementation

Β§πŸ—οΈ Automatic Code Assignment

You can configure automatic code assignment for variants without explicit codes:

use bizerror::BizError;

#[derive(BizError, thiserror::Error)]
#[bizconfig(auto_start = 1000, auto_increment = 10)]
pub enum ServiceError {
    #[error("Auto-assigned code")]
    AutoError1, // code: 1000

    #[bizcode(2001)]
    #[error("Explicit code")]
    ExplicitError, // code: 2001

    #[error("Another auto-assigned")]
    AutoError2, // code: 1010
}

Β§πŸ”§ Advanced Usage with Context

For scenarios requiring detailed context information:

use bizerror::*;

#[derive(BizError, thiserror::Error)]
pub enum ApiError {
    #[bizcode(8001)]
    #[error("Database connection failed")]
    DatabaseError(#[from] std::io::Error),
}

fn load_user_config() -> Result<String, ContextualError<ApiError>> {
    std::fs::read_to_string("config.json")
        .with_context("Loading user configuration")
}

match load_user_config() {
    Ok(config) => println!("Config loaded: {}", config),
    Err(e) => {
        println!("Error code: {}", e.code());
        println!("Context: {}", e.context());
        println!("Location: {}", e.location());
    }
}

Β§πŸ“Š Custom Code Types

You can use different types for error codes:

use bizerror::BizError;

// String codes
#[derive(BizError, thiserror::Error)]
#[bizconfig(code_type = "&'static str")]
pub enum StringError {
    #[bizcode("USER_NOT_FOUND")]
    #[error("User not found")]
    UserNotFound,

    #[error("Auto string code")]
    AutoString, // code: "0"
}

// Signed integer codes
#[derive(BizError, thiserror::Error)]
#[bizconfig(code_type = "i32", auto_start = -100)]
pub enum SignedError {
    #[error("Negative code")]
    NegativeCode, // code: -100
}

§🎨 Structured Debug Output

The derive macro automatically generates structured debug output:

let error = ApiError::ValidationError { field: "email".to_string() };
println!("{:?}", error);
// Output: ApiError { variant: "ValidationError", code: 4001, message: "Invalid input: email" }

Β§πŸ”— Error Chains and Context

Build comprehensive error chains with context:

use bizerror::*;

#[derive(BizError, thiserror::Error)]
pub enum ServiceError {
    #[bizcode(8001)]
    #[error("Database error: {0}")]
    DatabaseError(#[from] std::io::Error),
}

fn complex_operation() -> Result<String, ContextualError<ServiceError>> {
    // Multiple layers of context
    std::fs::read_to_string("data.json")
        .with_context("Loading configuration")
        .and_then(|_| {
            std::fs::read_to_string("user.json")
                .with_context("Loading user data")
        })
}

Β§πŸ† Best Practices

  1. Use meaningful error codes: Group related errors by code ranges

    • 1000-1999: Validation errors
    • 2000-2999: Authentication errors
    • 8000-8999: System errors
  2. Leverage automatic assignment: Use bizconfig for consistent code spacing

  3. Add context sparingly: Only use ContextualError when you need detailed debugging

  4. Chain errors properly: Use #[from] for automatic conversions

  5. Document error codes: Include code meanings in your API documentation

StructsΒ§

BizErrors
Business errors collection for aggregating multiple errors
ContextualError
Contextual error wrapper (only used when detailed context is needed)

TraitsΒ§

BizError
Core business error trait
BizErrorExt
BizError extension trait
OptionExt
Option extension trait
ResultExt
Result extension trait (simplified)

Derive MacrosΒ§

BizError