Skip to content

📘 Generate from OpenAPI

Generate Pydantic models from OpenAPI 3 schema definitions.

🚀 Quick Start

datamodel-codegen --input api.yaml --input-file-type openapi --output model.py

📝 Example

api.yaml
openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
servers:
  - url: http://petstore.swagger.io/v1
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of pets
          headers:
            x-next:
              description: A link to the next page of responses
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pets"
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
                x-amazon-apigateway-integration:
                  uri:
                    Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
                  passthroughBehavior: when_no_templates
                  httpMethod: POST
                  type: aws_proxy
    post:
      summary: Create a pet
      operationId: createPets
      tags:
        - pets
      responses:
        '201':
          description: Null response
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
                x-amazon-apigateway-integration:
                  uri:
                    Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
                  passthroughBehavior: when_no_templates
                  httpMethod: POST
                  type: aws_proxy
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pets"
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    x-amazon-apigateway-integration:
      uri:
        Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
      passthroughBehavior: when_no_templates
      httpMethod: POST
      type: aws_proxy
components:
  schemas:
    Pet:
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
          default: 1
        name:
          type: string
        tag:
          type: string
    Pets:
      type: array
      items:
        $ref: "#/components/schemas/Pet"
    Users:
      type: array
      items:
        required:
          - id
          - name
        properties:
          id:
            type: integer
            format: int64
          name:
            type: string
          tag:
            type: string
    Id:
      type: string
    Rules:
      type: array
      items:
        type: string
    Error:
      description: error result
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string
    apis:
      type: array
      items:
        type: object
        properties:
          apiKey:
            type: string
            description: To be used as a dataset parameter value
          apiVersionNumber:
            type: string
            description: To be used as a version parameter value
          apiUrl:
            type: string
            format: uri
            description: "The URL describing the dataset's fields"
          apiDocumentationUrl:
            type: string
            format: uri
            description: A URL to the API console for each API
    Event:
      type: object
      description: Event object
      properties:
        name:
          type: string
    Result:
        type: object
        properties:
          event:
            $ref: '#/components/schemas/Event'

✨ Generated model.py:

from __future__ import annotations

from pydantic import AnyUrl, BaseModel, Field, RootModel


class Pet(BaseModel):
    id: int
    name: str
    tag: str | None = None


class Pets(RootModel[list[Pet]]):
    root: list[Pet]


class User(BaseModel):
    id: int
    name: str
    tag: str | None = None


class Users(RootModel[list[User]]):
    root: list[User]


class Id(RootModel[str]):
    root: str


class Rules(RootModel[list[str]]):
    root: list[str]


class Error(BaseModel):
    code: int
    message: str


class Api(BaseModel):
    apiKey: str | None = Field(
        None, description='To be used as a dataset parameter value'
    )
    apiVersionNumber: str | None = Field(
        None, description='To be used as a version parameter value'
    )
    apiUrl: AnyUrl | None = Field(
        None, description="The URL describing the dataset's fields"
    )
    apiDocumentationUrl: AnyUrl | None = Field(
        None, description='A URL to the API console for each API'
    )


class Apis(RootModel[list[Api]]):
    root: list[Api]


class Event(BaseModel):
    name: str | None = None


class Result(BaseModel):
    event: Event | None = None

📖 readOnly / writeOnly Properties

OpenAPI 3.x supports readOnly and writeOnly property annotations:

  • 📤 readOnly: Property is only returned in responses (e.g., id, created_at)
  • 📥 writeOnly: Property is only sent in requests (e.g., password)

⚙️ Option: --read-only-write-only-model-type

This option generates separate Request/Response models based on these annotations.

Value Description
(not set) Default. No special handling (backward compatible)
request-response Generate only Request/Response models (no base model)
all Generate base model + Request + Response models

📋 Example Schema

openapi: "3.0.0"
info:
  title: Read Only Write Only Test API
  version: "1.0"
paths: {}
components:
  schemas:
    User:
      type: object
      required:
        - id
        - name
        - password
      properties:
        id:
          type: integer
          readOnly: true
        name:
          type: string
        password:
          type: string
          writeOnly: true
        created_at:
          type: string
          format: date-time
          readOnly: true
        secret_token:
          type: string
          writeOnly: true

✨ Generated Output

datamodel-codegen --input user.yaml --input-file-type openapi \
    --output-model-type pydantic_v2.BaseModel \
    --read-only-write-only-model-type all
from __future__ import annotations

from pydantic import AwareDatetime, BaseModel


class UserRequest(BaseModel):
    name: str
    password: str
    secret_token: str | None = None


class UserResponse(BaseModel):
    id: int
    name: str
    created_at: AwareDatetime | None = None


class User(BaseModel):
    id: int
    name: str
    password: str
    created_at: AwareDatetime | None = None
    secret_token: str | None = None

🎯 Usage Patterns

Use Case Recommended Option Generated Models
API client validation request-response UserRequest, UserResponse
Database ORM mapping (not set) User
Both client & ORM all User, UserRequest, UserResponse

🔗 Behavior with allOf Inheritance

When using allOf with $ref, fields from all referenced schemas are flattened into Request/Response models:

openapi: "3.0.0"
info:
  title: Read Only Write Only AllOf Test API
  version: "1.0"
paths: {}
components:
  schemas:
    Timestamps:
      type: object
      properties:
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true

    Credentials:
      type: object
      properties:
        password:
          type: string
          writeOnly: true
        api_key:
          type: string
          writeOnly: true

    User:
      allOf:
        - $ref: "#/components/schemas/Timestamps"
        - $ref: "#/components/schemas/Credentials"
        - type: object
          required:
            - id
            - name
          properties:
            id:
              type: integer
              readOnly: true
            name:
              type: string
            email:
              type: string

Generated UserRequest will exclude created_at, updated_at, and id because they are readOnly fields from the flattened Timestamps/User schemas. Generated UserResponse will exclude password and api_key because they are writeOnly fields from Credentials.

⚠️ Collision Handling

If a schema named UserRequest or UserResponse already exists, the generated model will be named UserRequestModel or UserResponseModel to avoid conflicts.

📤 Supported Output Formats

This option works with all output formats:

  • pydantic_v2.BaseModel
  • pydantic_v2.dataclass
  • dataclasses.dataclass
  • typing.TypedDict
  • msgspec.Struct

🔗 Supported $ref Types

readOnly/writeOnly resolution works with local and file reference types:

Reference Type Example Support
Local #/components/schemas/User ✅ Supported
File ./common.yaml#/User ✅ Supported

📖 See Also