Expand description
ApiError — a handler-facing error any plain axum handler can return.
Batteries-included apps write non-CRUD handlers that touch the ORM. Without
this, every one re-declares fn err500<E: Display>(e) -> (StatusCode, String)
and sprinkles .map_err(err500)? on every terminal (the single highest-volume
boilerplate observed in a live consumer). ApiError implements
From<WriteError> / From<sqlx::Error> / From<DynError> and IntoResponse,
so a handler returns Result<T, ApiError> and uses a bare ?:
use umbral::web::{ApiError, Json};
async fn get_post(Path(id): Path<i64>) -> Result<Json<Post>, ApiError> {
let post = Post::objects().filter(post::ID.eq(id)).first().await? // sqlx::Error -> 500
.ok_or_else(|| ApiError::not_found("no such post"))?; // -> 404
Ok(Json(post))
}Safe by default (WEB-5): a database/internal error logs the real cause
server-side and hands the client an opaque 500 — table names, SQL fragments
and constraint internals never reach the wire. A WriteError that is a
validation failure (required field, FK-not-found, format rule, …) becomes a
400 carrying the structured per-field error map.
Enums§
- ApiError
- A handler-facing error. Build explicit ones with the constructors, or let
?convert an ORM error (sqlx::Error/WriteError/DynError).