# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2026-06-03
First stable release. The public API is now covered by semantic versioning: breaking
changes will only ship in a future major version. No new functionality versus 0.10.0.
### Changed (breaking)
- Renamed `permissive_cors()` to `cors_permissive()` so both CORS helpers share a `cors_` prefix.
- Renamed `ApiError::unprocessable()` to `ApiError::unprocessable_entity()` to match the HTTP 422 status name and the other factory methods.
### Migration
- `permissive_cors()` -> `cors_permissive()`
- `ApiError::unprocessable(msg)` -> `ApiError::unprocessable_entity(msg)`
## [0.10.0] - 2026-06-03
### Added
- New `openapi` feature flag (pulls `utoipa` 5): `ApiError`, `ListResponse<T>`, `CursorResponse<T>`, and `HealthResponse` derive `utoipa::ToSchema`, so they can be referenced from a `utoipa` `OpenApi` document and appear in generated specs.
- Integration test verifying the response types register as OpenAPI components.
### Notes
- `ApiError::details` is mapped to an optional `Object` schema; `HealthResponse::status` is mapped to a `String`. Schema derivation only affects builds with the `openapi` feature enabled.
## [0.9.0] - 2026-06-03
### Added
- New `router` feature flag with service-wiring helpers:
- `health_routes(readiness)` - builds a state-generic `Router` with `/healthz` (liveness, always `ok`) and `/readyz` (readiness, runs the supplied async check and returns its `HealthResponse`, so `unhealthy` yields HTTP 503). Mergeable into a stateful app via `app.merge(...)`.
- `liveness` - a reusable liveness handler returning `HealthResponse::ok()`.
- New `cors` feature flag (pulls `tower-http`) with CORS helpers:
- `cors_allowing(origins)` - a `CorsLayer` for a known origin allow-list with the common REST methods, `content-type`/`authorization` headers, and credentials enabled.
- `permissive_cors()` - a permissive `CorsLayer` for local development.
- Router-based tests for the health probes and CORS layer (behind the respective features).
## [0.8.0] - 2026-06-03
### Added
- New `trace` feature flag with observability middleware:
- `propagate_request_id` - Axum middleware that reuses an incoming `x-request-id` header (or generates a UUID v4), stores it in request extensions, and echoes it on the response.
- `RequestId` - newtype stored in request extensions, with a `FromRequestParts` impl so handlers can extract the current request's correlation id.
- `trace_requests` - Axum middleware that emits an `info`-level `tracing` event per request with `method`, `path`, `status`, `latency_ms`, and `request_id`.
- `REQUEST_ID_HEADER` constant (`"x-request-id"`).
- Router-based integration tests for the middleware (behind the `trace` feature).
## [0.7.0] - 2026-06-03
### Added
- New `extract` feature flag with request extractors:
- `Pagination` - parses `limit`/`offset` query parameters; `limit` defaults to 50 and is clamped to `1..=100` (`Pagination::DEFAULT_LIMIT` / `Pagination::MAX_LIMIT`). Includes a `list_response(data, total)` helper that builds a `ListResponse`.
- `CursorPagination` - parses an optional `cursor` token plus a clamped `limit`. Includes a `cursor_response(data, next_cursor)` helper that builds a `CursorResponse` and derives `has_more` from the cursor.
- Invalid query strings reject with `400 Bad Request` and code `INVALID_QUERY`.
- `ValidatedJson<T>` extractor (requires the `validator` feature) - deserializes a JSON body and runs `validator` validation before the handler runs. Rejects with semantic `ApiError` bodies: `INVALID_JSON` (400), `INVALID_BODY` (422), `UNSUPPORTED_MEDIA_TYPE` (415), and `VALIDATION_ERROR` (422) with field-level details.
- Async extractor unit tests behind the relevant features.
### Changed
- The `validator` feature now also enables `validator/derive`, so `#[derive(Validate)]` is available wherever the feature is used.
- CI now runs clippy and the test suite with `--all-features` (and the default-feature test run) so feature-gated code is exercised.
## [0.6.0] - 2026-06-03
### Added
- First public release on crates.io.
- `LICENSE` file with the MIT license text.
- Package metadata: `authors`, `homepage`, `documentation`, and `rust-version` (MSRV 1.75).
- `[package.metadata.docs.rs]` with `all-features = true` so optional features render on docs.rs.
No API changes from 0.5.0.
## [0.5.0] - 2026-05-17
### Added
- Optional `sqlx` feature flag with sqlx 0.8 integration.
- `From<sqlx::Error> for ApiError` (when `sqlx` feature is enabled) with semantic HTTP status mapping: `RowNotFound` -> 404, unique/FK violations -> 409, check violations -> 422, pool errors -> 503, all others -> 500.
- Feature-gated unit tests for sqlx error conversion paths.
## [0.4.0] - 2026-05-17
### Added
- Optional `validator` feature flag with `validator` crate integration.
- `From<validator::ValidationErrors> for ApiError` (when `validator` feature is enabled).
- Deterministic validation error details shape under `details.fields` for field-level errors.
- Feature-gated tests for validator conversion paths and serialized payload structure.
## [0.3.0] - 2026-05-17
### Added
- `From<std::io::Error>` impl on `ApiError` - enables using `?` operator in handlers for I/O operations, automatically converting to HTTP 500.
- `From<serde_json::Error>` impl on `ApiError` - enables using `?` operator for JSON parsing errors.
- `ApiError::with_source(source_msg)` method - attach error source/context to details field for debugging chains: `ApiError::not_found("user").with_source("SELECT * FROM users")`.
- `CursorResponse<T>` - new cursor-based pagination type for large datasets and feeds, with `data`, `next_cursor: Option<String>`, and `has_more` fields.
- Unit tests for all new error conversion and cursor pagination features.
## [0.2.0] - 2026-05-17
### Added
- `ApiError` now implements `std::fmt::Display` and `std::error::Error`, enabling `?`-propagation in handlers.
- New `ApiError` factory methods: `too_many_requests` (429), `service_unavailable` (503), `not_implemented` (501).
- `HealthResponse::degraded()` - returns `{ "status": "degraded" }` with HTTP 200, for services operating in a reduced capacity.
- `HealthResponse::unhealthy()` - returns `{ "status": "unhealthy" }` with HTTP 503, for services unable to fulfill requests.
- GitHub Actions CI workflow: `cargo fmt --check`, `cargo clippy -- -D warnings`, `cargo test` on push and PR.
- Unit test suites in all three modules (`error`, `health`, `list`).
### Changed
- `HealthResponse` now stores an internal (non-serialized) `StatusCode` field so that `degraded` and `unhealthy` variants can return the correct HTTP status code via `IntoResponse`. No change to the serialized shape.
## [0.1.0] - 2026-01-01
### Added
- `ApiError` with factory methods for 400, 401, 403, 404, 409, 422, 500 (generic and db).
- `ListResponse<T>` for offset/limit paginated collections.
- `HealthResponse` with a single `ok()` constructor.