autogen-stedi
Auto-generated, strongly-typed, async Rust client for the Stedi APIs.
Every request/response type and API method is generated directly from Stedi's public
OpenAPI specs with
openapi-generator, so the surface stays faithful to the APIs and
updates automatically when a spec changes. A thin hand-written StediClient adds API-key auth on
top.
- Complete — all seven Stedi APIs (Claims, Core, Enrollment, Event Destinations, Healthcare, Manager, Payers), every endpoint and model.
- Async — built on
reqwest; works on any Tokio runtime. - Modular — every API is a Cargo feature, so you compile only what you use.
- Collision-free — each API lives in its own module (
claims,healthcare, …), so identically named models across specs never clash. - No magic — generated code is committed; no build scripts, no proc-macros, no codegen at build time.
Installation
[]
= "0.2"
= { = "1", = ["macros", "rt-multi-thread"] }
Compile only the APIs you need (faster builds):
[]
= { = "0.2", = false, = ["healthcare", "native-tls"] }
Note: with
default-features = falseyou must enable a TLS backend — eithernative-tlsorrustls— or HTTPS requests will fail at runtime.
Quick Start
use StediClient;
async
The seven APIs
Each Stedi API is a top-level module and a Cargo feature. The client accessor returns that API's
generated Configuration:
| Feature | Module | Accessor | Base URL |
|---|---|---|---|
claims |
claims |
client.claims() |
https://claims.us.stedi.com |
core |
core |
client.core() |
https://core.us.stedi.com |
enrollment |
enrollment |
client.enrollment() |
https://enrollments.us.stedi.com |
event-destinations |
event_destinations |
client.event_destinations() |
https://events.us.stedi.com |
healthcare |
healthcare |
client.healthcare() |
https://healthcare.us.stedi.com |
manager |
manager |
client.manager() |
https://manager.us.stedi.com |
payers |
payers |
client.payers() |
https://payers.us.stedi.com |
TLS backends (one required): native-tls (default) or rustls.
Authentication
All Stedi APIs authenticate with an API key sent in the Authorization header as Key <api-key>.
StediClient wires this into every service's Configuration:
use StediClient;
let client = new;
The base URL (including the dated API version such as /2024-04-01) is baked in from each spec. To
point at a proxy or mock server, mutate base_path on the returned configuration:
# use StediClient;
let client = new;
#
Error Handling
Generated functions return Result<T, apis::Error<E>>, where E is the endpoint-specific error
enum. Each service module has its own apis::Error, distinguishing transport errors,
(de)serialization errors, and structured API error responses:
use Error;
match some_call.await
How It's Generated
# Requires only a JDK (the generator JAR is fetched automatically).
generate.sh fetches all seven specs from the
Stedi OpenAPI repo, records their combined SHA-256 in
SPEC_HASH, runs openapi-generator (rust + reqwest template) on each, and vendors the generated
apis/ and models/ into a per-service module under src/<service>/. Because the rust generator
emits absolute crate::apis / crate::models paths, the script rewrites them to
crate::<service>::… so the code compiles inside a submodule. Finally it runs cargo check.
The generator version is pinned (GENERATOR_VERSION in generate.sh) and the JAR is downloaded
directly from Maven Central, so local and CI runs are byte-for-byte identical — there's no dependence
on a brew/npm install whose default generator version drifts. The run is idempotent: a fresh
generation reproduces the committed tree exactly. Date-time fields are typed as
chrono::DateTime<chrono::FixedOffset> (generator 7.15+).
Only the entry points are hand-written and protected from regeneration: Cargo.toml, src/lib.rs,
src/client.rs, plus README.md and CLAUDE.md. Everything under src/<service>/ is generated —
do not edit it by hand; fix the spec upstream or adjust generate.sh instead.
Staying in sync with the specs
The crate version is content-hash based, starting at 0.1.0. A scheduled GitHub Action
(update-spec.yml) regenerates from the live specs daily; when the combined hash changes it
bumps the patch version and opens a PR. Merging that PR tags the release and publishes the new
version to crates.io (tag-release.yml).
Publishing requires a CARGO_REGISTRY_TOKEN repository secret (a crates.io API token). The first
0.1.0 release should be published manually (cargo publish) to establish crate ownership;
automated patch releases flow through CI from then on.
Why auto-generated?
Hand-written SDKs drift from the API and accumulate subtle type mismatches. Generating from the specs keeps the client honest:
- Always current — a spec change becomes a PR, not a manually-tracked changelog entry.
- Exhaustive — every endpoint and model is present, not just the popular ones.
- Auditable — generated code is committed and reviewable; there's no build-time codegen to trust.
License
MIT