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

TypeUse it forImportant detail
ValidatedJson<T>A JSON request bodyT implements Serde Deserialize and iet_core::Validate; put this body-consuming extractor last in the handler arguments
ValidatedQuery<T>Query-string parametersCalls Validate; bound page sizes and allowlist sort choices in the input
ApiPath<T>Typed URL parametersParses without reflecting a submitted value into the rejection body
Axum State<S>The services your handler needsS 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

TypeHTTP behavior
Axum Json<T>Serializes the response, normally with status 200
Created<T>Serializes JSON with status 201
NoContentStatus 204 with no content
ApiErrorConverts 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:

rust
// Fragment: create_note and get_note are your handlers; state is your AppState.
let router = iet_http_axum::RestApi::new()
    .route("/notes", axum::routing::post(create_note))
    .route("/notes/{id}", axum::routing::get(get_note))
    .finish(state);

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 fieldDefaultAllowed values
HTTP_COMPRESSION_ENABLED / compression_enabledtruetrue, false
HTTP_COMPRESSION_MIN_BYTES / compression_min_bytes10241–65535
HTTP_COMPRESSION_LEVEL / compression_level61–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.

IET Framework documentation — built with the IET Framework.