HTTP building blocks
The notes application introduces these types in a working endpoint. This page is a lookup aid for your next endpoint, not a list you need to memorize first.
Receive an input
| Type | Use it for | Important detail |
|---|---|---|
ValidatedJson<T> | A JSON request body | T implements Serde Deserialize and iet_core::Validate; put this body-consuming extractor last in the handler arguments |
ValidatedQuery<T> | Query-string parameters | Calls Validate; bound page sizes and allowlist sort choices in the input |
ApiPath<T> | Typed URL parameters | Parses without reflecting a submitted value into the rejection body |
Axum State<S> | The services your handler needs | S is your concrete application state, not a runtime service registry |
Extractors parse a transport input. They do not decide whether the caller may read or change the requested resource. Authenticate the caller and enforce authorization in the operation; an integer ID successfully parsing is not an access grant.
Return a result
| Type | HTTP behavior |
|---|---|
Axum Json<T> | Serializes the response, normally with status 200 |
Created<T> | Serializes JSON with status 201 |
NoContent | Status 204 with no content |
ApiError | Converts an AppError into an HTTP problem response |
NoStore<R> | Adds Cache-Control: no-store to a response |
Created does not invent a Location header. Add one explicitly when your API
contract needs it. NoStore does not authenticate a request; use it to keep
private responses out of shared caches, including errors.
See validation and errors for error codes and the safe response body.
Compose the router
RestApi<S> wraps Axum route construction and finishes with your state:
// Fragment: create_note and get_note are your handlers; state is your AppState.
let router = new
.route
.route
.finish;
Use one method router per path. To serve GET and POST on the same path, register
get(list_notes).post(create_note) together rather than relying on ambiguous
duplicate registration.
The default body limit is 16 KiB. .body_limit(bytes)? accepts 1 byte through
16 MiB. The finished router adds problem responses for unmatched paths and
unsupported methods. It also adds HTTP telemetry middleware, but that does not
initialize an exporter or subscriber for the process.
Neither database access nor authentication is installed by finishing a router. Likewise, select a concrete limiter before adding routes if you want request budgets; see rate limiting.
Bind only when composition is ready
Enable the host Cargo feature on iet-http-axum to use HttpHost and
HostConfig. Build and validate your state and router first; then call
HttpHost::bind(config, router).await?.
HttpHost::run(shutdown) accepts a future that resolves when serving should
stop. It does not install an operating-system signal handler for you. The host
starts the drain deadline when shutdown begins, not when the server starts.
If you use a custom Axum server instead, you own that listener lifecycle and must provide socket peer information for peer-IP rate limits.
Response compression
Enable both host and compression Cargo features on iet-http-axum for
server-managed streaming gzip compression. With these features, compression is
enabled by default. Builds without compression retain their previous behavior.
Environment variable / HostConfig field | Default | Allowed values |
|---|---|---|
HTTP_COMPRESSION_ENABLED / compression_enabled | true | true, false |
HTTP_COMPRESSION_MIN_BYTES / compression_min_bytes | 1024 | 1–65535 |
HTTP_COMPRESSION_LEVEL / compression_level | 6 | 1–9; lower favors speed |
Environment settings apply when loading HostConfig::from_source (or using
HttpServer); constructing HostConfig directly uses its field values instead.
Configuration is validated before the listener binds.
Compression negotiates Accept-Encoding, preserves Vary, and streams without
collecting entire bodies. The minimum size applies to known-size bodies;
unknown-size eligible streams may compress regardless of their eventual size.
Only text, JSON, JavaScript, and XML content types are eligible. SSE, partial
responses, already encoded bodies, Cache-Control: no-store or no-transform,
and responses with the compression::NoCompression extension are excluded.
Do not compress secrets together with attacker-controlled content without a
security review (BREACH-style risks). The conservative no-store exclusion is
not a general side-channel defense. If a reverse proxy handles compression,
disable host compression with HTTP_COMPRESSION_ENABLED=false.
For an externally hosted Axum router, enable compression and apply
router.layer(iet_http_axum::compression::layer(1024, 6)?) instead. Do not also
enable host-managed compression for that router. Request decompression is not
provided by this feature.
Source: crates/features/iet-http-axum/src/routes.rs, extract.rs, error.rs,
lib.rs, and host.rs.