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.