rust_rfc7807_axum/lib.rs
1//! # rust-rfc7807-axum
2//!
3//! [Axum](https://docs.rs/axum) integration for
4//! [RFC 7807 Problem Details](https://www.rfc-editor.org/rfc/rfc7807).
5//!
6//! This crate provides [`IntoResponse`](axum_core::response::IntoResponse) for
7//! [`Problem`] and an [`ApiError`] wrapper that converts unknown errors into
8//! safe 500 responses that never leak internal details.
9//!
10//! # Quick Start
11//!
12//! ```rust,ignore
13//! use axum::{routing::get, Router};
14//! use rust_rfc7807::Problem;
15//! use rust_rfc7807_axum::ApiError;
16//!
17//! async fn handler() -> Result<String, ApiError> {
18//! Err(Problem::not_found()
19//! .detail("No user with ID 42")
20//! .code("USER_NOT_FOUND")
21//! .into())
22//! }
23//!
24//! let app: Router = Router::new().route("/users/:id", get(handler));
25//! ```
26//!
27//! The response will have:
28//! - HTTP status `404`
29//! - `Content-Type: application/problem+json`
30//! - A JSON body with `status`, `title`, `detail`, and `code` fields
31//!
32//! # Safe 500 Handling
33//!
34//! Use [`ApiError::internal`] to wrap any error into a safe 500 response.
35//! The original error is stored for logging but **never** serialized:
36//!
37//! ```
38//! use rust_rfc7807_axum::ApiError;
39//! use axum_core::response::IntoResponse;
40//!
41//! let err = ApiError::internal(std::io::Error::other("db connection refused"));
42//! let response = err.into_response();
43//!
44//! assert_eq!(response.status().as_u16(), 500);
45//! ```
46//!
47//! # Domain Error Conversion
48//!
49//! Implement [`IntoProblem`] on your domain errors, then convert via [`ApiError::from_domain`]:
50//!
51//! ```
52//! use rust_rfc7807::{IntoProblem, Problem};
53//! use rust_rfc7807_axum::ApiError;
54//!
55//! struct NotFound;
56//!
57//! impl IntoProblem for NotFound {
58//! fn into_problem(self) -> Problem {
59//! Problem::not_found().code("NOT_FOUND")
60//! }
61//! }
62//!
63//! let err = ApiError::from_domain(NotFound);
64//! ```
65//!
66//! # Features
67//!
68//! - **`tracing`**: Enables best-effort extraction of the current span's trace ID.
69
70mod api_error;
71mod trace;
72
73pub use api_error::ApiError;
74pub use trace::attach_trace;
75
76// Re-export core types for convenience.
77pub use rust_rfc7807::{IntoProblem, Problem, ValidationItem, APPLICATION_PROBLEM_JSON};
78
79#[cfg(test)]
80mod tests;