Skip to main content

Module error

Module error 

Source
Expand description

§Application-layer unified error type

This module defines AppError, the canonical error type returned by command/query handlers and the surrounding application-layer plumbing. It integrates seamlessly with the ErrorCode trait from eventide-domain so that the same code() / kind() / http_status() contract used in the domain layer can be re-exported all the way up to the HTTP/gRPC boundary.

§Architecture

┌─────────────────────────────────────────────────────────────────┐
│  eventide-domain                                                │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ ErrorKind   │  │ ErrorCode   │  │ DomainError             │  │
│  │ (category)  │  │ (trait)     │  │ impl ErrorCode ✓        │  │
│  └─────────────┘  └─────────────┘  └─────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│  eventide-application (this module)                             │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │ AppError                                                  │  │
│  │ impl ErrorCode ✓                                          │  │
│  │ impl From<DomainError> ✓                                  │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

§Quick start

§Using AppError

use eventide_application::error::{AppError, AppResult};
use eventide_domain::error::DomainError;

fn process_command() -> AppResult<String> {
    // Domain errors are converted into AppError automatically.
    let domain_result: Result<String, DomainError> =
        Err(DomainError::not_found("user 123"));
    domain_result?;

    Ok("success".to_string())
}

fn validate_input(input: &str) -> AppResult<()> {
    if input.is_empty() {
        return Err(AppError::validation("input cannot be empty"));
    }
    Ok(())
}

§Mapping to an API response

use axum::response::{IntoResponse, Response};
use axum::http::StatusCode;
use axum::Json;
use eventide_domain::error::ErrorCode;
use serde::Serialize;

#[derive(Serialize)]
pub struct ApiErrorResponse {
    pub code: String,
    pub message: String,
}

pub struct ApiError<E>(pub E);

impl<E: ErrorCode> IntoResponse for ApiError<E> {
    fn into_response(self) -> Response {
        let status = StatusCode::from_u16(self.0.http_status())
            .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

        let body = ApiErrorResponse {
            code: self.0.code().to_string(),
            message: self.0.to_string(),
        };

        (status, Json(body)).into_response()
    }
}

Structs§

AppError
Unified application-layer error type.

Type Aliases§

AppResult
Application-layer Result alias using AppError as the error type.