Thanks for helping make real-world OpenAPI documents easier to use from Rust. Bug reproductions with a small schema are especially valuable: generated-code problems are much faster to review when the wire shape is visible in a fixture.
- Use GitHub Discussions for usage questions and design exploration.
- Use the issue forms for reproducible bugs and concrete feature requests.
- For a larger generated-API or configuration change, open an issue before investing in an implementation so compatibility tradeoffs can be discussed.
- Follow the Code of Conduct and report vulnerabilities through SECURITY.md, not a public issue.
The project requires Rust 1.88 or newer, Git, and Bash. Clone with submodules so the vendored JSON Schema conformance corpus is available:
git clone --recurse-submodules https://github.com/gpu-cli/openapi-to-rust.git
cd openapi-to-rust
cargo testExternal contributors do not need the maintainers' Beads issue-tracking tool. Reference the public GitHub issue in your pull request when one exists.
src/analysis.rsconverts OpenAPI schemas and operations into generator IR.src/generator.rsemits models and coordinates generated files.src/client_generator.rsemits HTTP/SSE client operations.src/server/emits and manages opt-in Axum scaffolding.src/type_mapping.rsowns format strategies and dependency requirements.tests/fixtures/contains focused regression documents.tests/conformance/contains the compatibility catalog and reports.specs/contains the real-world corpus used by the compile gate.tests/corpus-manifest.txthashes the code that corpus generates, so an unintended change to real-world output fails CI.
- Add the smallest fixture that reproduces the OpenAPI shape.
- Add a behavioral assertion, snapshot, or generated scratch-crate compile test. Prefer behavior assertions when a full-file snapshot would be noisy.
- Implement the change without hand-editing checked-in generated examples.
- Run the checks proportional to the change.
- Explain generated API or wire-format compatibility in the pull request.
For insta snapshots:
cargo insta test
cargo insta reviewReview every changed snapshot. Do not accept broad snapshot churn without explaining why unrelated generated output changed.
Run the standard gate before opening a pull request:
cargo fmt --check
cargo clippy --all-features -- -D warnings
cargo nextest run --all-features
cargo test --doc --all-features
RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-featuresThe suite runs under nextest
(cargo install cargo-nextest --locked), which runs each test in its own
process. It cannot run doctests, so those keep going through the built-in
harness in the second command — running only cargo nextest run silently skips
them.
Also run the relevant distribution or corpus gate when touching these areas:
scripts/install-smoke.sh # packaging, CLI, or dependencies
scripts/spec-compile.sh anthropic openai # generator/client output
scripts/spec-compile.sh # broad generator/type changes
scripts/untyped-census.sh # anything that changes which fields get typedNothing generated is checked in, but generation is byte-deterministic and the
specs under specs/ are pinned, so any earlier revision's output can be
rebuilt on demand:
scripts/gen-diff.sh # vs the merge base with main
scripts/gen-diff.sh v0.15.0 # vs a release
GEN_DIFF_SPECS="anthropic openai" scripts/gen-diff.sh HEAD~1It builds the generator at that ref in a throwaway worktree, regenerates the
corpus on both sides, and prints per-spec churn plus any public item that
appeared or disappeared. Full per-spec diffs land in tmp/gen-diff/report/.
The base side is cached per commit, so repeat runs only pay for the working
tree. A cold full-corpus run is roughly a minute and a half.
tests/corpus-manifest.txt is the committed tripwire for the same thing: one
hashed line per generated file. When a change legitimately moves output,
inspect it with gen-diff.sh, then refresh the manifest with
scripts/corpus-manifest.sh so the review shows which specs moved. The
Generated by openapi-to-rust vX.Y.Z stamp is normalized away, so a version
bump alone never touches the manifest.
CI runs both. A pull request gets the corpus-diff job, which diffs against
the base of the pull request, puts the per-spec table in the job summary,
uploads the full diffs as an artifact, and then checks the manifest against the
corpus it already generated (--from tmp/gen-diff/head). Pushes to main and
scheduled runs get the manifest check on its own.
Both cover the types and client output. Server scaffolding is generated from
per-spec [server].operations selectors, so it has no uniform corpus pass yet.
scripts/untyped-census.sh rewrites tests/conformance/untyped-report.md,
which counts every generated field that carries serde_json::Value and says
why. Regenerate it when a change types fields that used to be opaque (or stops
typing ones that were), so the corpus delta is visible in review;
scripts/untyped-census.sh --check fails when it is stale. A recoverable
row means the schema carried type information the generator dropped — those are
defects with a fix, not shapes the spec left open.
The full corpus generates and compile-checks 55 OpenAPI documents and can take several minutes. CI runs a fast generation tier on pull requests and the full compile tier weekly or on manual dispatch.
Compile runs also generate deterministic, schema-valid JSON samples for each representable component model. Each sample is independently validated against the source OpenAPI JSON Schema, hydrated into the generated Rust type, serialized, validated again, and round-tripped a second time to require a stable wire representation. Start with one production spec while iterating:
scripts/spec-compile.sh anthropicThe full scripts/spec-compile.sh command applies the same check across the
55-spec compile suite. Its summary reports component and sample coverage plus
explicit schema skips. Set SPEC_COMPILE_SCHEMA_ROUNDTRIP=0 only when isolating
an unrelated compile failure; parse-only runs skip model round trips because
they do not compile generated Rust. Failed scratch crates and logs are retained
under tmp/spec-compile/.
Until 1.0, a minor release may correct generated Rust APIs that were incomplete or wrong on the wire. Even so, changes should be additive where practical. Call out all of the following in the pull request when applicable:
- generated method or model signature changes;
- serialized query, path, header, or body changes;
- new generated runtime dependencies or features;
- configuration migrations or default changes;
- OpenAPI constructs that remain unsupported.
Keep commits focused and use clear imperative messages. Maintainers may squash on merge.