Skip to main content

Crate baukit_http

Crate baukit_http 

Source
Expand description

Shared Axum middleware, HTTP telemetry, and public errors for Baukit services.

finalize applies one consistent request lifecycle: standard extractor and routing errors, request identity, W3C trace extraction and response propagation, route-template spans, HTTP RED metrics, panic and timeout envelopes, body and concurrency limits, and explicit CORS.

§Example

use axum::{Router, routing::get};
use baukit_http::{HttpOptions, RequestId, finalize};

async fn hello(request_id: RequestId) -> String {
    format!("hello from request {}", request_id.as_str())
}

let options = HttpOptions::default()
    .with_allowed_origins(["https://app.example.com"])?
    .with_additional_allowed_headers(["accept", "x-webhook-secret"])?
    .with_json_rejection_code("invalid_json")?;
let app = finalize(Router::new().route("/hello", get(hello)), options);

pagination adds keyset pagination whose opaque cursors are bound to the request filters, and classify_http_status turns an upstream response into a RetryClass so outbound clients share one retry policy.

§Paginated handler

use axum::extract::Query;
use baukit_http::{ApiError, Page, PageKey, PageParams, ResponseEnvelope};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Deserialize)]
struct ListQuery {
    limit: Option<i64>,
    cursor: Option<String>,
    category: Option<String>,
}

#[derive(Serialize)]
struct Filters {
    category: Option<String>,
}

#[derive(Clone, Serialize)]
struct Item {
    id: Uuid,
    name: String,
}

#[derive(Serialize)]
struct PageMeta {
    next_cursor: Option<String>,
}

async fn list(
    Query(query): Query<ListQuery>,
) -> Result<ResponseEnvelope<Vec<Item>, PageMeta>, ApiError> {
    let params = PageParams::new(query.limit, query.cursor)?;
    let filters = Filters { category: query.category };
    let after = params.decode_cursor(&filters)?;

    // Fetch `params.fetch_limit()?` rows ordered by (name, id), starting
    // after `after.page_key::<String>()?` when it is present.
    let _ = after;
    let rows: Vec<Item> = Vec::new();

    let page = Page::from_rows(rows, &params, &filters, |item| {
        PageKey::new(item.name.clone(), item.id)
    })?;
    Ok(ResponseEnvelope::new(
        page.items,
        PageMeta { next_cursor: page.next_cursor },
    ))
}

This crate records HTTP metrics through the metrics facade and never installs a recorder. The recorder owner must configure http_request_duration_seconds with DURATION_BUCKETS.

Re-exports§

pub use pagination::Cursor;
pub use pagination::DEFAULT_PAGE_LIMIT;
pub use pagination::MAX_PAGE_LIMIT;
pub use pagination::Page;
pub use pagination::PageKey;
pub use pagination::PageParams;
pub use pagination::PaginationError;
pub use retry::RetryClass;
pub use retry::RetryHeaderOptions;
pub use retry::classify_http_status;
pub use retry::classify_http_status_with_options;
pub use retry::classify_transport_error;
pub use retry::retry_after_from_headers;
pub use retry::retry_after_from_headers_at;
pub use retry::retry_after_from_headers_with_options;
pub use retry::retry_after_from_headers_with_options_at;
pub use metrics;

Modules§

pagination
Keyset pagination with opaque cursors bound to the request filters.
retry
Classification of upstream HTTP responses and transport failures.

Structs§

ApiError
A safe public API error rendered in Baukit’s standard JSON envelope.
ApiJson
A JSON body extractor whose rejections use Baukit’s standard error envelope.
ApiPath
Backward-compatible name for Path. A route-path extractor whose rejections use Baukit’s standard error envelope.
ApiQuery
Backward-compatible name for Query. A query-string extractor whose rejections use Baukit’s standard error envelope.
ErrorBody
The error body nested inside ErrorEnvelope.
ErrorEnvelope
The shared public error response envelope.
HttpOptions
Configuration for the shared HTTP layer stack.
JsonRejectionCodes
Stable error codes for each JSON extractor rejection class.
Path
A route-path extractor whose rejections use Baukit’s standard error envelope.
Query
A query-string extractor whose rejections use Baukit’s standard error envelope.
RequestId
A request identifier accepted from the client or generated as a UUID.
RequestLocale
A locale selected from the configured supported set for one request.
RequestLocaleConfig
Product-owned locale choices used by RequestLocale.
ResponseEnvelope
A fully typed success-response envelope.
Rfc3339DateTime
An API timestamp with one JSON and OpenAPI representation: an RFC 3339 string with OpenAPI date-time format.

Enums§

HttpOptionsError
An invalid shared HTTP layer option.
LocaleQueryOverride
Controls whether a decoded query parameter overrides Accept-Language.
RequestLocaleConfigError
Invalid request-locale configuration.
RequestLocaleRejection
Predictable malformed-input failures from RequestLocale.

Constants§

DURATION_BUCKETS
Required Prometheus buckets for HTTP_REQUEST_DURATION_SECONDS, in seconds.
HTTP_REQUESTS_IN_FLIGHT
Gauge metric for active HTTP requests, labeled method and route.
HTTP_REQUESTS_TOTAL
Counter metric for completed HTTP requests, labeled method, route, and status.
HTTP_REQUEST_DURATION_SECONDS
Histogram metric for HTTP request seconds, labeled method, route, and status.
MAX_ACCEPT_LANGUAGE_BYTES
Maximum combined Accept-Language header length inspected by RequestLocale.
MAX_LOCALE_QUERY_BYTES
Maximum raw query length inspected by RequestLocale.
MAX_SUPPORTED_LOCALES
Maximum number of locales in a RequestLocaleConfig.
X_REQUEST_ID
The standard request ID header.

Functions§

extract_trace_context
Extracts W3C trace context from request headers using the global propagator.
finalize
Finalizes a public router with standard 404/405 envelopes and HTTP layers.
inject_current_trace_context
Injects the current tracing span’s OpenTelemetry context into outbound headers.
inject_trace_context
Injects context into outbound headers using the global W3C propagator.
layers
Applies the complete Baukit HTTP defaults stack to an Axum router.