oas3-rs
Rust structures and tools to parse, navigate, and validate OpenAPI v3.1.x specifications with order-preserving maps.
Repository Health
Technical Analysis
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_jsonfor JSON specs always available, plusfrom_yaml/to_yamlbehind the optionalyaml-specfeature- An order-preserving
Map<K, V>(backed byindexmap) so serialized output keeps the key order of the original document instead of re-sorting it $refresolution viaObjectOrReference<T>and theFromReftrait, 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
printerexample 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
$refpointers in a spec to inline the referenced schema, parameter, or response for downstream tooling - Building spec-driven conformance testing (as the workspace’s companion
roastcrate 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.