axum_api_kit/lib.rs
1//! Shared response types for Axum JSON APIs.
2//!
3//! Provides building blocks that every Axum CRUD service needs but always
4//! re-defines from scratch:
5//!
6//! - [`ApiError`] - a machine-readable JSON error body with `code`, `message`, and optional
7//! `details`, plus factory helpers that return `(StatusCode, Json<ApiError>)` tuples ready
8//! for use with Axum's [`IntoResponse`](axum::response::IntoResponse). Supports `From`
9//! conversions for common error types. With the optional `validator` feature enabled,
10//! also supports converting `validator::ValidationErrors` into structured field errors.
11//! With the optional `sqlx` feature enabled, also supports converting `sqlx::Error` into
12//! semantically correct HTTP status codes (404, 409, 422, 503, 500).
13//! - [`ListResponse<T>`] - a generic offset/limit paginated collection response with `data`,
14//! `total`, `limit`, and `offset` fields.
15//! - [`CursorResponse<T>`] - a generic cursor-based paginated collection response for large
16//! datasets or feeds, with `data`, `next_cursor`, and `has_more` fields.
17//! - [`HealthResponse`] - a health-check response with `status` field supporting `ok`,
18//! `degraded`, and `unhealthy` states.
19//!
20//! # Quick Start
21//!
22//! ```rust,no_run
23//! use axum::{Json, http::StatusCode, response::IntoResponse};
24//! use axum_api_kit::{ApiError, ListResponse, CursorResponse, HealthResponse};
25//! use serde::Serialize;
26//!
27//! #[derive(Serialize)]
28//! struct Item { id: String }
29//!
30//! async fn list_items() -> impl IntoResponse {
31//! let items = vec![Item { id: "1".into() }];
32//! Json(ListResponse { data: items, total: 1, limit: 50, offset: 0 })
33//! }
34//!
35//! async fn feed_items(cursor: Option<String>) -> impl IntoResponse {
36//! let items = vec![Item { id: "1".into() }];
37//! CursorResponse { data: items, next_cursor: Some("abc".into()), has_more: true }
38//! }
39//!
40//! async fn get_item() -> impl IntoResponse {
41//! ApiError::not_found("item not found")
42//! }
43//!
44//! async fn health() -> impl IntoResponse {
45//! HealthResponse::ok()
46//! }
47//! ```
48
49mod cursor;
50mod error;
51mod health;
52mod list;
53
54pub use cursor::CursorResponse;
55pub use error::ApiError;
56pub use health::HealthResponse;
57pub use list::ListResponse;