oas3-rs

Rust structures and tools to parse, navigate, and validate OpenAPI v3.1.x specifications with order-preserving maps.

Library
Cargo
v0.22.0
78stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
79/100Good
Development Activity96
Maintenance96
Community44
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture82
Code Quality88
Innovation78
Learning Curve65

oas3 is a Rust crate that deserializes, represents, and validates OpenAPI v3.1.x documents as strongly typed structures. It covers the full spec surface — paths, operations, parameters, request/response bodies, components, security schemes, callbacks, and JSON Schema-based schemas — so applications can load a spec from JSON or YAML and work with it as native Rust types instead of untyped JSON values.

A distinguishing detail is its order-preserving Map type: OpenAPI documents (paths, component maps, schema properties, extensions) keep the key order they had in the source file through a round trip of deserialize-then-serialize, which matters for tools that diff or regenerate specs. YAML support is behind an opt-in yaml-spec feature so JSON-only consumers can skip that dependency, and the crate is the foundation for a companion roast crate in the same workspace that runs conformance tests against a running API using a parsed spec.

What You Get

  • A complete typed model of the OpenAPI v3.1.x object graph: Spec, Info, Components, Paths, Operation, Parameter, RequestBody, Response, Header, SecurityScheme, Callback, Tag, and more
  • from_json / to_json for JSON specs always available, plus from_yaml / to_yaml behind the optional yaml-spec feature
  • An order-preserving Map<K, V> (backed by indexmap) so serialized output keeps the key order of the original document instead of re-sorting it
  • $ref resolution via ObjectOrReference<T> and the FromRef trait, turning #/components/... reference strings back into the referenced typed object
  • Typed, derive_more-based error enums (spec::Error, RefError, SchemaError) instead of stringly-typed error messages
  • A runnable printer example showing a full read-spec-then-reserialize round trip

Common Use Cases

  • Loading a service’s OpenAPI YAML/JSON file and walking its paths and schemas to generate client code, docs, or mock servers
  • Validating that a hand-written or generated OpenAPI document conforms to the v3.1.x structure before publishing it
  • Resolving $ref pointers in a spec to inline the referenced schema, parameter, or response for downstream tooling
  • Building spec-driven conformance testing (as the workspace’s companion roast crate does, sending requests to a live API and checking responses against the parsed spec)
  • Re-serializing a spec after programmatic edits while preserving the original field and property ordering

Under The Hood

Architecture The crate is organized around a single entry type, spec::Spec, re-exported at the crate root alongside a custom order-preserving Map type (src/map.rs, src/lib.rs). The spec module (src/spec/mod.rs) fans out into one file per OpenAPI object — operation.rs, parameter.rs, schema.rs, security_scheme.rs, path_item.rs, and roughly twenty more — each defining its own typed struct/enum with serde derives, and the module re-exports them all as a flat public API. Cross-references between spec objects ($ref strings) are handled uniformly through ObjectOrReference<T> and a FromRef trait (src/spec/ref.rs), which resolves a reference against a &Spec rather than requiring callers to walk components maps by hand. This keeps parsing, representation, and reference-resolution as separate concerns, and the design lets the workspace’s second crate, roast, build API conformance testing directly on top of the typed Spec without touching JSON.

Tech Stack oas3 is pure Rust with serde/serde_json for the core (de)serialization and an optional yaml_serde dependency behind the yaml-spec feature flag for YAML support. Structural pieces come from indexmap (the order-preserving Map), http (for method/status types), semver (validating the spec’s declared OpenAPI version), regex and once_cell for the lazily-compiled $ref pattern, and derive_more for boilerplate-free Display/Error/From impls on the error enums. The crate lives in a Cargo workspace alongside a roast conformance-testing crate and integration-tests, uses just as a task runner, targets a pinned MSRV (1.87) verified in CI, and is distributed purely as a library — no binary target beyond the illustrative printer example.

Code Quality Tests are colocated with the code they exercise (#[test] blocks inside lib.rs and most spec/*.rs files, ~34 test functions total) rather than a separate top-level tests/ tree, exercising serde round-trips and edge cases like reference resolution and schema type parsing. CI runs the suite via cargo-nextest against both MSRV and stable toolchains, workspace-level Clippy lints deny rust-2018-idioms, nonstandard-style, and future-incompatible and warn on missing-debug-implementations and missing-docs, and Codecov tracks coverage. Errors are modeled as typed enums (spec::Error, RefError, SchemaError) built with derive_more, never raw strings or panics in the public API, and public items are documented under the missing-docs lint.

API Design The public surface is deliberately small: four top-level functions (from_json/to_json, from_yaml/to_yaml) get a caller from a string to a fully typed Spec and back in one call, with YAML support opt-in via a feature flag so JSON-only users don’t pull in the extra dependency. Reference resolution follows one consistent pattern (ObjectOrReference::resolve(&spec)) across every referencable object type rather than bespoke lookup methods per type, and the order-preserving Map is a drop-in enough replacement for a standard map that most callers won’t need to think about it unless they care about serialization order. The one-argument printer example demonstrates the whole read-then-write loop in under fifteen lines.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search