[Crystal] Add request-signing seam (`Configuration#sign_request`)

Merged
N-
4mo ago
+191-0

Description

Adds a public request-signing seam to the crystal client generator. It lets a
consumer inject a per-request signature (OVH $1$+SHA1, AWS SigV4, RFC 9421, ...) without
subclassing or patching the generated code.

Why

Configuration#apply_auth! applies the static credentials declared in the OpenAPI spec
(apiKey / basic / bearer / oauth). A request signature is a hash computed per request over
the method, full URL, body and a timestamp — recomputed on every call. It is not expressible
as an OpenAPI security scheme, so apply_auth! cannot carry it and a procedural extension
point is needed.

How

Configuration gains an optional sign_request hook:

property sign_request : Proc(Symbol, String, String?, HTTP::Headers,
                             Hash(String, String | Array(String)), Nil)? = nil

Connection#request invokes it after apply_auth! and just before the Crest call, so
the hook sees the serialized body and the final method/URL and can mutate headers/query in
place. Left nil = no signing. apply_auth! is unchanged (fully backward compatible).

The Crest client has no middleware stack, so this differs in form from a Faraday middleware
pile — it is a single callback at the one point in Connection#request where everything a
signature needs is already in local scope.

Scope

Pure template change — no codegen Java. Touches configuration.mustache +
connection.mustache, adds a README section with an illustrative OVH example (and a note that
the hook runs before Crest re-encodes the query string), and regenerates the crystal and
crystal-qdrant samples. No OVH-specific code lives in the generator.

Testing

  • New unit test CrystalClientCodegenTest#testConfigurationExposesSignRequestSeam (red → green); full class 28 tests, 0 failures.
  • Regenerated samples: diff limited to configuration.cr + connection.cr (+ README) in both crystal and crystal-qdrant. The added lines are crystal tool format-clean.

PR checklist

  • Read the contribution guidelines.
  • Rebuilt and regenerated the affected Crystal samples (./bin/generate-samples.sh bin/configs/crystal.yaml bin/configs/crystal-qdrant.yaml). Only the Crystal generator's output changes.
  • @mention the technical committee for review.

cc @wing328 — small, backward-compatible extension point for the Crystal generator (request signing that OpenAPI security schemes cannot model).


Summary by cubic

Adds a request-signing hook to the Crystal client generator so consumers can compute per-request signatures (e.g., OVH, AWS SigV4, RFC 9421) without patching generated code. Backward compatible; static auth via apply_auth! is unchanged.

  • New Features
    • Added Configuration#sign_request Proc(method, url, body, headers, query).
    • Invoked from Connection#request after apply_auth! and before the Crest call; mutate headers/query to sign.
    • Off by default (nil) with no behavior change.
    • Clarified docs: url excludes the query string; body is nil for form/multipart. Updated README with example and notes, added unit test, and regenerated Crystal and Qdrant samples.