#codegen #openapi #cli

build openapi-model-generator

A robust Rust library and CLI tool for generating type-safe Rust models from OpenAPI 3.0 specifications with advanced composition support

9 releases (4 breaking)

new 0.5.0 Feb 2, 2026
0.4.1 Dec 5, 2025
0.4.0 Nov 14, 2025
0.3.1 Nov 4, 2025
0.1.0 Jul 14, 2025

#137 in Build Utils

MIT/Apache

110KB
2K SLoC

OpenAPI Model Generator

A Rust library and CLI tool for generating Rust models from OpenAPI specifications. This utility automatically creates Rust structures based on schemas from OpenAPI (Swagger) documentation.

Features

  • OpenAPI 3.0 specification support with full schema parsing
  • YAML and JSON format support for input specifications
  • Automatic generation of Rust structures with Serde attributes
  • Schema Composition Support: Complete implementation of OpenAPI composition patterns:
    • allOf - Combines multiple schemas into a single struct
    • oneOf / anyOf - Generates tagged union enums with proper serde configuration
  • Advanced Type Support:
    • Enum Support - Automatically generates Rust enums from OpenAPI string schemas with enumeration constraints.
    • UUID fields (format: uuidUuid type)
    • DateTime fields (format: date-timeDateTime<Utc> type)
    • Nested types and arrays with proper generic handling
  • Custom Type Support:
    • x-rust-type extension - Replace generated models with custom Rust types (type aliases)
    • x-rust-attrs extension - Add custom Rust attributes to generated types
    • Works with any schema type (object, enum, oneOf, etc.)
    • Support for x-rust-type on individual properties
  • Smart Field Deduplication: Automatically resolves duplicate field names in allOf compositions
    • Preserves concrete types (e.g., i64, String) over generic serde_json::Value
    • Prevents compilation errors from duplicate struct fields
  • Array Composition Support: Full support for arrays with complex item types
    • Arrays with oneOf items → Vec<UnionEnum>
    • Arrays with any schema composition pattern
  • Request Bodies Support: Full parsing and model generation from components.requestBodies
  • Smart Code Generation:
    • Required vs optional field detection (Option<T> for nullable fields)
    • PascalCase naming for generated request/response models
    • Reference resolution across schema definitions
  • Clean Code Output: Properly formatted Rust code with comprehensive serde annotations

Installation

As a CLI tool

cargo install openapi-model-generator

As a library dependency

Add to your Cargo.toml:

[dependencies]
openapi-model-generator = "0.5.0"

Usage

Command Line Interface

omg -i path/to/openapi.yaml -o ./generated

Parameters

  • -i, --input - Path to the OpenAPI specification file (YAML or JSON)
  • -o, --output - Path to the output directory (default: ./generated)

Library Usage

use openapi_model_generator::{parse_openapi, generate_models};
use std::fs;

// Parse OpenAPI specification
let openapi_spec = fs::read_to_string("openapi.yaml")?;
let openapi: openapiv3::OpenAPI = serde_yaml::from_str(&openapi_spec)?;

// Generate models
let (models, requests, responses) = parse_openapi(&openapi)?;
let generated_code = generate_models(&models, &requests, &responses)?;

// Write to file
fs::write("models.rs", generated_code)?;

Example

Source OpenAPI schema:

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        email:
          type: string
        age:
          type: integer
        is_active:
          type: boolean
      required:
        - id
        - name
        - email

Generated Rust code:

use serde::{Serialize, Deserialize};
use uuid::Uuid;
use chrono::{DateTime, NaiveDate, Utc};

#[derive(Debug, Serialize, Deserialize)]
pub struct User {
    #[serde(rename = "id")]
    pub id: Uuid,
    #[serde(rename = "name")]
    pub name: String,
    #[serde(rename = "email")]
    pub email: String,
    #[serde(rename = "age")]
    pub age: Option<i64>,
    #[serde(rename = "is_active")]
    pub is_active: Option<bool>,
}

Using Custom Types with x-rust-type

You can use the x-rust-type extension to replace generated models with your own custom types:

components:
  schemas:
    User:
      type: object
      x-rust-type: crate::domain::User
      description: "Custom domain user type"
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
    
    Status:
      type: string
      enum: [active, inactive, pending]
      x-rust-type: common::enums::Status

Generated Rust code:

/// Custom domain user type
pub type User = crate::domain::User;

/// Status
pub type Status = common::enums::Status;

This allows you to:

  • Reuse existing domain models instead of generating duplicates
  • Integrate with types from other crates
  • Maintain a clean separation between API models and domain models

Using Custom Attributes with x-rust-attrs

You can use the x-rust-attrs extension to add arbitrary Rust attributes to generated types:

components:
  schemas:
    User:
      type: object
      x-rust-attrs:
        - "#[serde(rename_all = \"camelCase\")]"
      properties:
        user_id:
          type: string
          format: uuid
        first_name:
          type: string
        is_active:
          type: boolean
      required:
        - user_id
        - first_name
    
    Status:
      type: string
      enum: [ACTIVE, INACTIVE, PENDING]
      x-rust-attrs:
        - "#[serde(rename_all = \"UPPERCASE\")]"
    
    Product:
      type: object
      x-rust-attrs:
        - "#[derive(Serialize, Deserialize)]"
        - "#[serde(deny_unknown_fields)]"
      properties:
        id:
          type: string
        name:
          type: string

Generated Rust code:

/// User
#[serde(rename_all = "camelCase")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
    pub user_id: Uuid,
    pub first_name: String,
    pub is_active: Option<bool>,
}

/// Status
#[serde(rename_all = "UPPERCASE")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Status {
    ACTIVE,
    INACTIVE,
    PENDING
}

/// Product
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Product {
    pub id: Option<String>,
    pub name: Option<String>,
}

This allows you to:

  • Add custom serde rules (rename_all, deny_unknown_fields, tag, etc.)
  • Enable additional trait derives
  • Apply conditional compilation attributes (cfg, cfg_attr)
  • Use custom validation macros
  • Works together with x-rust-type extension

Recent Updates (v0.5.0)

  • Added: Support for x-rust-type extension on individual properties
  • Improved: Multi-line description formatting for better documentation
  • Fixed: Duplicate field names in allOf compositions with different types
  • Added: Support for arrays with oneOf items
  • Improved: Enum variant names automatically converted to PascalCase
  • Added: Module-level documentation comments in generated files
  • Improved: Code quality - removed non-English comments, fixed clippy warnings

Development

Dependencies

  • Rust 1.70 or higher
  • Cargo

Building

cargo build

Running Tests

cargo test

Examples

The generator supports complex OpenAPI patterns including schema composition:

  • UUID and DateTime handling - Automatic type conversion for formatted strings
  • Schema composition with allOf - Inheritance and field merging
  • Tagged unions with oneOf/anyOf - Automatic enum generation with proper serde tags

Changelog

See CHANGELOG.md for detailed information about releases and changes.

License

MIT

Dependencies

~10–15MB
~176K SLoC