Skip to content

RequestContext field exposure: decide #[non_exhaustive] / accessor policy before adding fields #89

@iainmcgin

Description

@iainmcgin

RequestContext is a pub-fields struct without #[non_exhaustive]:

pub struct RequestContext {
    pub headers: HeaderMap,
    pub deadline: Option<Instant>,
    pub extensions: http::Extensions,
}

This means adding a field is a SemVer-major break for anyone who constructed a RequestContext literal (e.g. in tests). We have already grown this struct once (the mTLS work added connection-scoped data via extensions precisely to avoid a new field), and the ergonomics review identified several more candidate fields: service name, method name, RPC kind, negotiated protocol — all of which generic middleware/logging needs and which neither tonic's Request<T> nor today's RequestContext carry.

We should decide the evolution policy now, before 1.0:

Option A — #[non_exhaustive] + accessors. Make fields pub(crate), add headers(), headers_mut(), deadline(), extensions(), extensions_mut() accessors plus a builder for tests. Future fields are additive. This is the conventional Rust-library answer.

Option B — commit to the open struct. Keep fields pub and accept that any new request-scoped data must flow through extensions. Cheaper today, but pushes useful fields (method name, protocol) into a typed-map lookup with no discoverability.

Either choice should also add accessor helpers for the well-known extension types so users don't write .extensions.get::<PeerAddr>().unwrap() (which compiles, runs in tests, and panics in production because the Server inserts PeerAddr but axum integrations may not):

impl RequestContext {
    pub fn peer_addr(&self) -> Option<SocketAddr>;
    pub fn peer_certs(&self) -> Option<&[CertificateDer]>;
}

Scope

Small but SemVer-relevant. Best landed before any field is added under pressure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions