aws/internal/client/runtime

Shared runtime for awsJson1_0 + awsJson1_1 generated clients.

Generated per-service modules carry the per-operation build_* / parse_* codec pair plus the service-level metadata (endpoint prefix, signing name, region). They call into invoke here for everything else: credential resolution, endpoint URL construction, SigV4 signing, HTTP dispatch, response parsing.

This keeps the generated code small: one invoke call per operation rather than ~30 lines of glue per op duplicated 57× across DynamoDB.

Types

Configuration carried inside every generated Client. See module docs for what’s threaded through where.

endpoint_rule_set and endpoint_params are the Smithy endpoint resolution inputs. When endpoint_rule_set is Some, every invoke call computes the request URL by walking the rule set against endpoint_params merged with {Region: region} and any operation- specific parameters threaded through invoke_with_endpoint_params. When it’s None, endpoint_url is used verbatim — that’s the pre-M3 behaviour the runtime keeps as a fallback.

pub type ClientConfig {
  ClientConfig(
    provider: credentials.Provider,
    region: String,
    endpoint_prefix: String,
    signing_name: String,
    endpoint_url: String,
    http_send: fn(request.Request(BitArray)) -> Result(
      response.Response(BitArray),
      http_send.HttpError,
    ),
    streaming_http_send: fn(request.Request(BitArray)) -> Result(
      response.Response(streaming.StreamingBody),
      http_send.HttpError,
    ),
    timestamp: fn() -> String,
    retry_strategy: retry.Strategy,
    endpoint_rule_set: option.Option(endpoints.RuleSet),
    endpoint_params: dict.Dict(String, endpoints.Value),
    sigv4a_signer: option.Option(Sigv4aSigner),
  )
}

Constructors

  • ClientConfig(
      provider: credentials.Provider,
      region: String,
      endpoint_prefix: String,
      signing_name: String,
      endpoint_url: String,
      http_send: fn(request.Request(BitArray)) -> Result(
        response.Response(BitArray),
        http_send.HttpError,
      ),
      streaming_http_send: fn(request.Request(BitArray)) -> Result(
        response.Response(streaming.StreamingBody),
        http_send.HttpError,
      ),
      timestamp: fn() -> String,
      retry_strategy: retry.Strategy,
      endpoint_rule_set: option.Option(endpoints.RuleSet),
      endpoint_params: dict.Dict(String, endpoints.Value),
      sigv4a_signer: option.Option(Sigv4aSigner),
    )

    Arguments

    streaming_http_send

    Streaming HTTP sender used by @streaming operations. Buffered callers (the majority of AWS APIs) keep using http_send; the codegen for streaming operations threads this one instead so large object GETs (S3) or long-lived subscription streams (Kinesis, Bedrock) can consume chunks incrementally without the runtime buffering the full response.

    sigv4a_signer

    SigV4a signing opt-in. When Some, prepare_signed_request derives an EC scalar from the provider’s IAM credentials and signs via sigv4a.sign_with_credentials instead of the default sigv4.sign. Required for S3 Multi-Region Access Points and any other endpoint that demands AWS4-ECDSA-P256.

Errors surfaced from a generated <op>(client, input) call.

pub type ClientError {
  CredentialsError(credentials.ProviderError)
  TransportError(http_send.HttpError)
  DecodeError(reason: String)
  ServiceError(status: Int, error_type: String, body: BitArray)
}

Constructors

Per-Client SigV4a opt-in state. Carries the region set the signature binds to (X-Amz-Region-Set); the IAM credentials themselves still flow through the regular config.provider, so credential rotation / refresh continues to work via the existing credentials_cache path. normalize_path defaults to True (the typical AWS service); S3 callers need False so object keys with . / .. survive the canonical-request step.

pub type Sigv4aSigner {
  Sigv4aSigner(region_set: List(String), normalize_path: Bool)
}

Constructors

  • Sigv4aSigner(region_set: List(String), normalize_path: Bool)

Values

pub fn check_error_type_matches(
  headers: dict.Dict(String, String),
  body: BitArray,
  expected_local: String,
) -> Result(Nil, String)

Discriminator check for protocol-test error-shape dispatchers. Used by the generated parse_<err>_response function: if the wire-side discriminator (header or body) resolves to expected_local, the response was routed to the right error shape and the dispatcher reports Ok(Nil). The runner’s response-side assertion is binary — Ok vs Error — so returning Nil is enough.

The runner hands fixture headers through with their literal-case keys (X-Amzn-Errortype), but extract_error_type expects the lowercased form that the real-request path produces via headers_to_dict. We lowercase here so the helper matches HTTP’s case-insensitive header semantics regardless of which call-site invokes it.

pub fn default_config(
  region: String,
  endpoint_prefix: String,
  signing_name: String,
) -> ClientConfig

Sensible default config given a region. Credentials default to the standard chain (env → web-identity → SSO → profile → process → ECS → IMDS); callers swap in a custom provider via with_credentials_provider, matching the convention every other AWS SDK follows.

pub fn default_endpoint(
  endpoint_prefix: String,
  region: String,
) -> String
pub fn error_type_matches(
  error_type: String,
  local: String,
) -> Bool

Match an AWS error_type wire value against a local Smithy shape name. Used by the generated per-op translate_<op>_error dispatchers. error_type already passes through normalise_error_type (namespace + suffix stripped) at the invoke layer, so a plain equality check suffices; we keep this behind a helper to give the codegen one stable call-site.

pub fn extract_error_type(
  headers: dict.Dict(String, String),
  body: BitArray,
) -> String

Pull the wire-error-type local name out of a response. Looks at the X-Amzn-Errortype header first (restJson1, awsJson*); falls back to the body for __type / code / <Code> (covers JSON and XML error shapes). The returned string is the local shape name — namespace prefix, URI suffix, and Smithy [Charlie,foo,bar] suffix are all stripped. Exposed for codegen-emitted error-shape protocol test dispatchers; the in-process retry path uses it via the ServiceError discriminator.

pub fn invoke(
  config: ClientConfig,
  built: #(String, String, dict.Dict(String, String), BitArray),
  parse: fn(Int, dict.Dict(String, String), BitArray) -> Result(
    output,
    String,
  ),
) -> Result(output, ClientError)

Run one operation end-to-end. See module docs for the pipeline.

Operations that need to thread rule-set parameters known only to the op itself (e.g. S3’s Bucket) should use invoke_with_endpoint_params instead and pass those parameters through op_params.

pub fn invoke_streaming(
  config: ClientConfig,
  built: #(String, String, dict.Dict(String, String), BitArray),
) -> Result(streaming.Response, ClientError)

Streaming-response variant of invoke. Builds + signs the request exactly like invoke, but dispatches through streaming_http_send (chunked transport) and returns the raw Response(StreamingBody) so callers can consume the body incrementally — fold chunk-by-chunk via streaming.fold_chunks, decode event-stream frames via event_stream.fold_events, or stream-to-disk without buffering.

Used by generated codegen for operations whose output carries @streamingS3.GetObject for multi-GB downloads, Transcribe.StartStreamTranscription and Kinesis.SubscribeToShard for event-stream responses, etc.

Error responses (non-2xx) are materialised via streaming.to_bit_array_max(body, 1 MiB) so error_type extraction works on the JSON/XML error body the same way as invoke. A response body that exceeds the 1 MiB cap on the error path surfaces as DecodeError since we can’t safely extract a typed error from an oversized error body.

Retry is intentionally NOT wrapped around streaming_http_send at this layer — replaying a streaming request after a transient failure is op-specific (idempotent vs. mutating). Callers that want retry on a streaming op should layer it themselves or drop down to the buffered invoke.

pub fn invoke_streaming_with_endpoint_params(
  config: ClientConfig,
  op_params: dict.Dict(String, endpoints.Value),
  built: #(String, String, dict.Dict(String, String), BitArray),
) -> Result(streaming.Response, ClientError)

invoke_streaming with per-op endpoint-rule-set parameters (the streaming-side counterpart to invoke_with_endpoint_params).

pub fn invoke_with_endpoint_params(
  config: ClientConfig,
  op_params: dict.Dict(String, endpoints.Value),
  built: #(String, String, dict.Dict(String, String), BitArray),
  parse: fn(Int, dict.Dict(String, String), BitArray) -> Result(
    output,
    String,
  ),
) -> Result(output, ClientError)

Same as invoke but with extra rule-set parameters merged in for this operation only — used by generated S3 ops to supply Bucket/Key etc. without leaking them onto the client config. If the client has no endpoint_rule_set, op_params is ignored (the static endpoint_url is used).

pub fn invoke_with_endpoint_params_and_host_prefix(
  config: ClientConfig,
  op_params: dict.Dict(String, endpoints.Value),
  host_prefix: option.Option(String),
  built: #(String, String, dict.Dict(String, String), BitArray),
  parse: fn(Int, dict.Dict(String, String), BitArray) -> Result(
    output,
    String,
  ),
) -> Result(output, ClientError)

invoke_with_endpoint_params with an already-substituted host prefix. Codegen passes Some(prefix) for ops carrying @smithy.api#endpoint.hostPrefix — the template (e.g. "{RequestRoute}.") is expanded against the input’s @hostLabel members in the generated wrapper, mirroring the Rust SDK’s read_before_execution interceptor.

pub fn translate_service_error(
  err: ClientError,
  decoders: List(#(String, fn(String) -> Result(t, Nil))),
  on_transport: fn(String) -> t,
  on_unknown: fn(String, Int, String) -> t,
) -> t

Generic translator from the runtime’s ClientError to a per-op typed-error enum. Each generated translate_<op>_error is a one-liner that supplies its operation’s decoder table plus constructors for the always-present *Transport and *Unknown variants. Saves ~15–25 LOC/op vs the previous open-coded nested match — see Pass 3c in plan.md.

decoders is a list of (wire_error_type_local_name, decoder) pairs. The first pair whose error_type matches gets to attempt the decode; if its decoder returns Error(Nil), we fall back to on_unknown with the textified body so the caller still sees something useful instead of a panic.

pub fn with_credentials_provider(
  config: ClientConfig,
  provider: credentials.Provider,
) -> ClientConfig

Override the credentials provider — use for non-default profiles, in-process static creds, or any custom resolution chain.

pub fn with_endpoint_param(
  config: ClientConfig,
  name: String,
  value: endpoints.Value,
) -> ClientConfig

Set a single client-level endpoint-rule-set parameter (e.g. "UseFIPS" -> BoolVal(True)). Operation-specific params (S3 Bucket, Key) are threaded per-call via invoke_with_endpoint_params.

pub fn with_endpoint_rule_set(
  config: ClientConfig,
  rule_set: endpoints.RuleSet,
) -> ClientConfig

Attach a Smithy endpoint rule set. When set, the runtime walks the rule set per request to compute the endpoint URL — the value passed in via with_endpoint_url (or default_endpoint) is then ignored except as a fallback when the rule set is cleared. Use this from generated service constructors that embed their service’s rule set.

pub fn with_endpoint_url(
  config: ClientConfig,
  url: String,
) -> ClientConfig

Override the request endpoint URL. Used for LocalStack, FIPS endpoints, custom DNS, and pre-signed-URL replay flows.

When a Smithy endpoint rule set is attached (the codegen wires one on every generated service that declares one), the override is threaded into the rule set as the standard Endpoint parameter rather than replacing endpoint_url outright. AWS rule sets honour this parameter via an early-branch rule like case isSet(Endpoint) -> endpoint { url: "{Endpoint}" }, so the override wins consistently across all services that declare an Endpoint rule-set parameter.

The static endpoint_url is also updated so services without a rule set continue to honour the override via the fallback path.

pub fn with_http2(config: ClientConfig) -> ClientConfig

Switch the streaming sender to the HTTP/2 variant. httpc adds {http_version, "HTTP/2"} to its option list; servers that don’t speak HTTP/2 negotiate down to HTTP/1.1 via ALPN, so calls keep working even when the peer doesn’t support it. Buffered requests (http_send) are unaffected — HTTP/2 is for high-throughput streaming endpoints (S3 multipart, Bedrock streaming, Transcribe).

Pair with with_streaming_http_send for finer control (e.g. a stubbed sender in tests that needs HTTP/2 wiring elsewhere).

pub fn with_http_send(
  config: ClientConfig,
  send: fn(request.Request(BitArray)) -> Result(
    response.Response(BitArray),
    http_send.HttpError,
  ),
) -> ClientConfig
pub fn with_max_attempts(
  config: ClientConfig,
  n: Int,
) -> ClientConfig

Tune just the retry attempt budget without replacing the whole strategy. Equivalent to with_retry_strategy(config, retry.with_max_attempts(config.retry_strategy, n)), but reads as a single knob — the common case for production tuning. Pass 1 to disable retries entirely (single attempt per request), 5 for long-running batch workloads that tolerate extra wait, etc.

pub fn with_retry_strategy(
  config: ClientConfig,
  strategy: retry.Strategy,
) -> ClientConfig

Override the retry strategy used to wrap http_send. Pass retry.standard() for the AWS-standard 3-attempt backoff (the default), or retry.adaptive(bucket) to add the token-bucket gate.

pub fn with_sigv4a_path_normalization(
  config: ClientConfig,
  normalize: Bool,
) -> ClientConfig

Override the SigV4a normalize_path knob. No-op when the client hasn’t opted into SigV4a yet (with_sigv4a_region_set not called). Pass False for S3 — its object-key paths can carry . / .. that the RFC 3986 dot-segment removal would otherwise strip.

pub fn with_sigv4a_region_set(
  config: ClientConfig,
  region_set: List(String),
) -> ClientConfig

Opt the Client into SigV4a (asymmetric ECDSA P-256) signing for every request. region_set becomes the X-Amz-Region-Set header — single-region callers pass ["us-east-1"], multi-region callers pass the full list. Required for S3 Multi-Region Access Points.

normalize_path defaults to True; S3 callers should follow up with with_sigv4a_path_normalization(client, False) so keys containing . / .. survive the canonical-request step.

pub fn with_streaming_http_send(
  config: ClientConfig,
  send: fn(request.Request(BitArray)) -> Result(
    response.Response(streaming.StreamingBody),
    http_send.HttpError,
  ),
) -> ClientConfig

Override the streaming HTTP sender. Use for tests (stub the transport), for forcing the buffered-then-streamed path via http_send.lift_to_streaming(custom_buffered), or to inject a future custom transport (proxy, gRPC tunnel, etc.).

Search Document