oas3-gen 0.26.2

A rust type generator for OpenAPI v3.1.x specification.
# (OAS3-GEN) OpenAPI 3.1+ Rust Generator

```rust
//     ██████╗  █████╗ ███████╗██████╗        ██████╗ ███████╗███╗   ██╗
//    ██╔═══██╗██╔══██╗██╔════╝╚════██╗      ██╔════╝ ██╔════╝████╗  ██║
//    ██║   ██║███████║███████╗ █████╔╝█████╗██║  ███╗█████╗  ██╔██╗ ██║
//    ██║   ██║██╔══██║╚════██║ ╚═══██╗╚════╝██║   ██║██╔══╝  ██║╚██╗██║
//    ╚██████╔╝██║  ██║███████║██████╔╝      ╚██████╔╝███████╗██║ ╚████║
//     ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═════╝        ╚═════╝ ╚══════╝╚═╝  ╚═══╝
```

<!-- prettier-ignore-start -->
[![crates.io](https://img.shields.io/crates/v/oas3-gen?label=latest)](https://crates.io/crates/oas3-gen)
[![dependency status](https://deps.rs/crate/oas3-gen/0.26.2/status.svg)](https://deps.rs/crate/oas3-gen/0.26.2)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)
[![openapi](https://badgen.net/badge/OAS/v3.1.2?list=1&color=purple)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.2.md)
<!-- prettier-ignore-end -->

`oas3-gen` is a command-line interface (CLI) for generating idiomatic Rust type definitions from an OpenAPI v3.1.x specification. The tool produces clean, production-ready code designed for seamless integration into any Rust project. Its primary function is to provide a robust and reliable method for type generation, ensuring the resulting code is correct, efficient, and well-documented.

Generated output preserves the declaration order written in the OpenAPI document for schemas, fields, enum variants, union variants, operations, and header constants. Map-like generated types use `indexmap::IndexMap`, and arrays marked with `uniqueItems: true` use `indexmap::IndexSet` so runtime insertion order is preserved too. Pass `--no-ordered-collections` to opt out of the `indexmap` runtime types and emit `std::collections::HashMap<String, T>` plus `Vec<T>` instead.

## Quick Start

### 1. Installation

Install the tool directly from crates.io using `cargo`.

```zsh
cargo install oas3-gen
```

#### Alternative build with [Nix]https://nixos.org/

 -  Make sure you have `nix` installed or install it with:
    ```shell
    sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon
    ```
 -  Now simply run it with:
    - `nix run github:eklipse2k8/oas3-gen` will run the binary, fetching the git repo automatically.
    - Or locally in the repo with `nix run`
    - To globally install use `nix profile install`

This takes cares of build dependencies (`openssl`, `pkg-config`) and they are packaged reproducibly and defined in `flake.nix`.
A development shell is included and can be accessed by running `nix develop` or use `direnv allow` if available.

### 2. Generation

Provide a path to an OpenAPI specification (JSON or YAML) and specify an output file for the generated Rust code. The format is auto-detected based on file extension.

```zsh
# generate types (structs and enums)
oas3-gen generate -i path/to/openapi.json -o path/to/types.rs
oas3-gen generate -i path/to/openapi.yaml -o path/to/types.rs

# generate client operations
oas3-gen generate client -i path/to/openapi.json -o path/to/client.rs

# generate server module (types.rs, server.rs, mod.rs)
oas3-gen generate server-mod -i path/to/openapi.json -o path/to/output/
```

#### Example

Consider the following Pet OpenAPI schema definition in `fixtures/petstore.json`:

```json
{
  "Pet": {
    "type": "object",
    "required": ["id", "name"],
    "properties": {
     "id": {
      "type": "integer",
      "format": "int64"
     },
     "name": {
      "type": "string"
     },
     "tag": {
      "type": "string"
     }
    }
  }
}
```

Executing `oas3-gen` produces the corresponding Rust types.

```rust
// src/types.rs

use serde::Deserialize;

#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)]
pub struct Pet {
  pub id: i64,
  pub name: String,
  pub tag: Option<String>,
}
```

### Server Generation

The `server-mod` command generates an axum-based server trait with handler functions and router configuration.

```zsh
oas3-gen generate server-mod -i path/to/openapi.json -o path/to/output/
```

This generates three files:
- `types.rs` - All request/response types
- `server.rs` - Server trait, handlers, and router
- `mod.rs` - Module exports

#### Generated Server Trait

```rust
// server.rs

pub trait ApiServer: Send + Sync {
    fn list_pets(&self, request: ListPetsRequest)
        -> impl std::future::Future<Output = anyhow::Result<ListPetsResponse>> + Send;

    fn create_pet(&self, request: CreatePetRequest)
        -> impl std::future::Future<Output = anyhow::Result<CreatePetResponse>> + Send;

    fn get_pet_by_id(&self, request: GetPetByIdRequest)
        -> impl std::future::Future<Output = anyhow::Result<GetPetByIdResponse>> + Send;
}
```

#### Implementing the Server

```rust
use generated::{ApiServer, ListPetsRequest, ListPetsResponse, /* ... */};

#[derive(Clone)]
struct MyServer {
    db: DatabasePool,
}

impl ApiServer for MyServer {
    fn list_pets(&self, request: ListPetsRequest)
        -> impl std::future::Future<Output = anyhow::Result<ListPetsResponse>> + Send
    {
        async move {
            let pets = self.db.query_pets(request.query.limit).await?;
            Ok(ListPetsResponse::Ok(pets))
        }
    }
    // ... implement other methods
}

#[tokio::main]
async fn main() {
    let server = MyServer { db: create_pool().await };
    let app = generated::router(server);
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}
```

The generated router automatically:
- Extracts path, query, and header parameters
- Deserializes request bodies (JSON, form, multipart)
- Routes requests to the correct handler based on path and HTTP method
- Converts response enums to proper HTTP responses with status codes

## Key Features

| Feature | Description |
|---------|-------------|
| Custom Formats | Use `serde_as` to parse formats |
| Cycle Detection | Prevents infinite type recursion |
| Doc Comments | Schema descriptions become rustdoc |
| Enum Helpers | Ergonomic is_/as_ methods |
| Enum Modes | Merge, preserve, or relaxed |
| Event stream | Simple event stream capture if media-type is specified |
| JSON/YAML Support | Auto-detects format from file extension |
| OData Support | Optional @odata.* field handling |
| OpenAPI 3.1 | Most common spec parsing support |
| Operation Filtering | Include/exclude specific operations |
| Operation Types | Request/response type generation |
| Order Preserving | Mirrors OpenAPI declaration order in generated code |
| Schema Composition | Handles allOf/oneOf/anyOf correctly |
| Server Generation | Axum server trait scaffolding |
| Serde Integration | Automatic derive for serialization |
| Smart Naming | Auto-detects camelCase/snake_case conventions |
| Validation | Constraint attributes from spec |
| Builder Pattern | Optional `bon` integration for ergonomic struct construction |
| Webhooks | Generates structs from Webhook components |

### Missing features

* OAS 3.1 Links and `$dynamic-ref` (oas3 doesn't support this yet)
* OAS 3.2 Event-stream support
* External schema references
* HTTP schema references and fetching

### Command-Line Options

```text
OpenAPI to Rust code generator

Usage: oas3-gen [OPTIONS] <COMMAND>

Commands:
  list      List information from OpenAPI specification
  generate  Generates idiomatic, type-safe Rust code from an OpenAPI v3.1 (OAS31) specification
  help      Print this message or the help of the given subcommand(s)

Options:
  -h, --help     Print help
  -V, --version  Print version

Terminal Output:
      --color <WHEN>   Coloring [default: auto] [possible values: always, auto, never]
      --theme <THEME>  Theme [default: auto] [possible values: dark, light, auto]
```

#### Generate Command

```text
Generates idiomatic, type-safe Rust code from an OpenAPI v3.1 (OAS31) specification

Usage: oas3-gen generate [OPTIONS] --input <FILE> [MODE]

Arguments:
  [MODE]  Sets the generation mode [default: types] [possible values: types, client, client-mod, server-mod]

Required:
  -i, --input <FILE>   Path to the OpenAPI specification file
  -o, --output <PATH>  Path for generated output (file for types/client, directory for client-mod/server-mod)

Code Generation:
  -C, --visibility <PUB>       Module visibility for generated items [default: public] [possible values: public, crate, file]
      --odata-support          Enable OData-specific field optionality rules (makes @odata.* fields optional on concrete types)
      --enum-mode <ENUM_MODE>  Specifies how to handle enum case sensitivity and duplicates [default: merge] [possible values: merge, preserve, relaxed]
      --no-helpers             Disable generation of ergonomic helper methods for enum variants
  -c, --customize <TYPE=PATH>  Custom serde_as type overrides (format: type_name=custom::Path)
      --all-headers            Emit header constants for all parameters defined in components, not just those used in operations
      --enable-builders        Enable bon builder derives on schema structs and builder methods on request structs
      --doc-format             Format documentation comments using mdformat (requires mdformat installed)
      --no-ordered-collections Emit std::collections::HashMap and Vec instead of indexmap::IndexMap/IndexSet for map fields and uniqueItems arrays

Operation Filtering:
      --only <id_1,id_2,...>     Include only the specified comma-separated operation IDs
      --exclude <id_1,id_2,...>  Exclude the specified comma-separated operation IDs
      --all-schemas              Generate all schemas, even those unreferenced by selected operations
```

#### List Command

```text
List information from OpenAPI specification

Usage: oas3-gen list [OPTIONS] <COMMAND>

Commands:
  operations  List all operations defined in the OpenAPI specification
  help        Print this message or the help of the given subcommand(s)

Options:
  -h, --help     Print help
  -V, --version  Print version

Terminal Output:
      --color <WHEN>   Coloring [default: auto] [possible values: always, auto, never]
      --theme <THEME>  Theme [default: auto] [possible values: dark, light, auto]
```

### Examples

```zsh
# Basic usage to generate a client module from a json schema file
oas3-gen generate client-mod -i openapi.json -o generated

# Generate a server module with axum trait scaffolding
oas3-gen generate server-mod -i openapi.json -o generated

# Or generate types and client code individually ...

# Generate types with crate-level visibility
oas3-gen generate types -i openapi.json -o types.rs -C crate
oas3-gen generate client -i openapi.json -o client.rs -C crate

# Generate all schemas types including unused ones
oas3-gen generate -i openapi.json -o types.rs --all-schemas

# Generate code for specific operation types only
oas3-gen generate -i openapi.json -o types.rs --only create_user,get_user,update_user

# Generate code excluding certain operation types
oas3-gen generate -i openapi.json -o types.rs --exclude delete_user,list_users

# Generate all schemas but only specific operation types (includes unreferenced schemas)
oas3-gen generate -i openapi.json -o types.rs --all-schemas --only create_user

# Enable OData support for Microsoft Graph
oas3-gen generate -i graph-api.json -o types.rs --odata-support

# Enable relaxed (case-insensitive) enum deserialization
oas3-gen generate -i openapi.json -o types.rs --enum-mode relaxed

# Enable custom parsing through serde_as traits
oas3-gen generate client-mod -i openapi.json -o generated --customize datetime=MyCustomDateTime

# Enable bon builder derives for ergonomic struct construction
oas3-gen generate client-mod -i openapi.json -o generated --enable-builders

# Opt out of indexmap runtime types (emit std::collections::HashMap and Vec)
oas3-gen generate client-mod -i openapi.json -o generated --no-ordered-collections

# Format documentation comments with mdformat
oas3-gen generate client-mod -i openapi.json -o generated --doc-format

# List all operations in the specification
oas3-gen list operations -i openapi.json
```

## Documentation Formatting with `mdformat`

The `--doc-format` flag pipes generated documentation comments through
[mdformat](https://github.com/executablebooks/mdformat), a CommonMark-compliant
Markdown formatter. This reformats long descriptions from OpenAPI `summary` and
`description` fields into consistently wrapped, readable rustdoc comments. Lines are wrapped at 100 characters and markdown structure (headings, blockquotes, lists) is normalized.

The `mdformat` binary must be available on your `PATH` when using `--doc-format`.
If it is not installed, the command will fail with an error. The flag is entirely
optional and has no effect on the structure or correctness of generated code.

## License

This project is licensed under the MIT License. See the [LICENSE.md](LICENSE.md) file for details.

```md
Copyright (c) 2026 Individual contributors
```

### Contribution

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more details on how to get started.

All contributions submitted for inclusion in the work must be code-signed by an active _HUMAN_ GitHub account and shall be licensed as MIT, without any additional terms or conditions. No bot or agent generated contributions will be accepted and will be immediately rejected.

See [OpenAPI v3.1.2]: <https://spec.openapis.org/oas/v3.1.2>