Expand description
Shared error layer for the DiiDi Travel monorepo.
Every service throws the same AppError — categorized, code-stable, context-rich, and
source-chained. Cross-cutting concerns (HTTP status, gRPC status, JSON wire shape, severity ↔
tracing-level mapping) live here so each service doesn’t reinvent them.
§Quick start
use diidi_travel_common_error::{AppError, ErrorCategory, Result, ResultExt, bail, ensure};
fn lookup(id: u64) -> Result<&'static str> {
ensure!(id != 0, ErrorCategory::Validation, "user.id.invalid", "id must be > 0");
if id == 1 {
return Ok("alice");
}
bail!(ErrorCategory::NotFound, "user.not_found", "no user with id {id}");
}
fn handle() -> Result<()> {
let _name = lookup(0).err_context("operation", "handle")?;
Ok(())
}§Shape
AppError— main typeErrorCategory— broad classification with HTTP/gRPC mappingErrorCode— stable, machine-readable identifierErrorContext— open-ended key/value metadataSeverity— used for logging routingErrorResponse— wire shape for replying to callersResult—std::result::Result<T, AppError>aliasResultExt— fluent error decoration onResult- macros:
app_error!,bail!,ensure!
Re-exports§
pub use crate::category::ErrorCategory;pub use crate::category::UnknownCategory;pub use crate::code::ErrorCode;pub use crate::code::UNSPECIFIED;pub use crate::context::ErrorContext;pub use crate::error::AppError;pub use crate::error::BoxedStdError;pub use crate::response::ErrorResponse;pub use crate::result::Result;pub use crate::result::ResultExt;pub use crate::severity::Severity;
Modules§
- category
- Broad error classification. Each category maps to standard HTTP / gRPC status codes so the
same
AppErrorcan be surfaced through REST, gRPC, or message-bus replies without re-encoding. - code
- Stable identifier for an error. Use
const-able static codes for the common cases (const USER_NOT_FOUND: ErrorCode = ErrorCode::from_static("user.not_found");) and theErrorCode::newconstructor when the code is composed at runtime. - context
- Open-ended key/value metadata attached to an
AppError. Values areserde_json::Valueso anything serializable can land here without expanding the public API. - error
- The flagship
AppErrortype. Designed to be the one error every service throws — flexible enough to encode the failure (category + stable code + free-text message + arbitrary context) and scalable across REST / gRPC / message-bus boundaries via the conversions inconvert. - macros
- Ergonomic macros that mirror
anyhow::{bail, ensure}but produceAppError. - response
- Wire-shape for sending an
AppErrorback to a caller — typed for REST/JSON today, but the same shape works in any envelope that can carry a JSON object. - result
- Result alias and ergonomic extension trait for layering context onto fallible operations.
- severity
- Severity of an
AppError. Maps cleanly totracing::Levelso consumers can route the error through the logging stack without an extra translation table.