OpenAPI 3.1 Reference: Schemas, Components, Webhooks, SDK Generation & Tooling
OpenAPI 3.1 is the standard for documenting HTTP APIs. It’s the spec that powers Swagger UI, Redoc, SDK generators, and mock servers. Getting the spec right means your docs, client libraries, and validation all work from the same source of truth.
1. Document Structure & Info
openapi.yaml skeleton — info, servers, tags, and security schemes
openapi: "3.1.0"
info:
title: Orders API
version: "2.0.0"
description: |
REST API for order management.
[Changelog](https://example.com/changelog)
contact:
name: Platform Team
email: platform@example.com
license:
name: MIT
identifier: MIT
servers:
- url: https://api.example.com/v2
description: Production
- url: https://api.staging.example.com/v2
description: Staging
- url: http://localhost:8000
description: Local development
tags:
- name: orders
description: Order lifecycle management
- name: users
description: User accounts
# Security schemes (define once, apply globally or per-endpoint):
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
apiKeyHeader:
type: apiKey
in: header
name: X-API-Key
# Apply globally (can be overridden to {} on public endpoints):
security:
- bearerAuth: []
2. Paths, Parameters & Request Bodies
Define endpoints, path/query/header parameters, and JSON request bodies
paths:
/orders:
get:
summary: List orders
operationId: listOrders # unique ID — used by SDK generators
tags: [orders]
parameters:
- name: status
in: query # path | query | header | cookie
required: false
schema:
type: string
enum: [pending, processing, completed, cancelled]
description: Filter by order status
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
"200":
description: Paginated list of orders
content:
application/json:
schema:
$ref: "#/components/schemas/OrderList"
post:
summary: Create order
operationId: createOrder
tags: [orders]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateOrderRequest"
example:
customerId: "cust_123"
items:
- productId: "prod_456"
quantity: 2
responses:
"201":
description: Order created
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"422":
$ref: "#/components/responses/ValidationError"
/orders/{orderId}:
parameters:
- name: orderId
in: path
required: true
schema:
type: string
pattern: "^ord_[a-z0-9]{12}$"
get:
summary: Get order by ID
operationId: getOrder
tags: [orders]
responses:
"200":
description: Order details
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"404":
$ref: "#/components/responses/NotFound"
3. Schemas & Components
Reusable schemas with $ref, composition (allOf/oneOf/anyOf), and discriminators
components:
schemas:
Order:
type: object
required: [id, customerId, status, total, createdAt]
properties:
id:
type: string
readOnly: true # excluded from request schemas
example: ord_a1b2c3d4e5f6
customerId:
type: string
status:
type: string
enum: [pending, processing, completed, cancelled]
total:
type: number
format: float
minimum: 0
items:
type: array
items:
$ref: "#/components/schemas/OrderItem"
createdAt:
type: string
format: date-time
readOnly: true
OrderItem:
type: object
required: [productId, quantity, unitPrice]
properties:
productId:
type: string
quantity:
type: integer
minimum: 1
unitPrice:
type: number
# Composition with discriminator (polymorphism):
PaymentMethod:
oneOf:
- $ref: "#/components/schemas/CreditCard"
- $ref: "#/components/schemas/BankTransfer"
- $ref: "#/components/schemas/Crypto"
discriminator:
propertyName: type # field that tells the parser which schema
mapping:
credit_card: "#/components/schemas/CreditCard"
bank_transfer: "#/components/schemas/BankTransfer"
crypto: "#/components/schemas/Crypto"
# allOf (extend/merge schemas):
AdminUser:
allOf:
- $ref: "#/components/schemas/User" # inherit all User fields
- type: object
properties:
permissions:
type: array
items:
type: string
# Reusable responses:
responses:
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
ValidationError:
description: Request validation failed
content:
application/json:
schema:
type: object
properties:
errors:
type: array
items:
type: object
properties:
field: {type: string}
message: {type: string}
4. Tooling — Validation, Docs & SDK Generation
Lint the spec, serve Swagger UI locally, generate TypeScript/Python clients
# Validate the spec (catches $ref errors, missing schemas, etc.): npx @redocly/cli lint openapi.yaml # best validator — checks rules + $refs npx swagger-codegen validate openapi.yaml # Redocly lint rules (.redocly.yaml): extends: [recommended] rules: operation-operationId: error # require operationId on every endpoint tag-description: warn no-unused-components: warn # Serve Swagger UI locally (zero install via Docker): docker run --rm -p 8080:8080 -v $(pwd)/openapi.yaml:/tmp/spec.yaml -e SWAGGER_JSON=/tmp/spec.yaml swaggerapi/swagger-ui # Serve Redoc (cleaner UI): npx @redocly/cli preview-docs openapi.yaml # Generate TypeScript fetch client: npx openapi-typescript openapi.yaml --output src/types/api.ts # or full SDK: docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/openapi.yaml -g typescript-fetch -o /local/generated/ # Generate Python client: docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/openapi.yaml -g python -o /local/generated-python/ # Mock server (for frontend dev before backend is ready): npx @stoplight/prism-cli mock openapi.yaml --port 4010 # curl http://localhost:4010/orders → returns example data from spec
5. Webhooks, Links & OpenAPI 3.1 Features
Document webhooks, response links, and OpenAPI 3.1 JSON Schema alignment
# OpenAPI 3.1 key changes from 3.0:
# - Full JSON Schema 2020-12 compatibility (type: [string, null] instead of nullable: true)
# - webhooks: top-level key for documenting outbound webhooks
# - schema.$schema field supported
# Webhooks (document what you SEND, not receive):
webhooks:
orderCompleted:
post:
summary: Order completed notification
description: Sent when an order transitions to 'completed' status
requestBody:
content:
application/json:
schema:
type: object
required: [event, data, timestamp]
properties:
event: {type: string, example: order.completed}
data:
$ref: "#/components/schemas/Order"
timestamp:
type: string
format: date-time
responses:
"200":
description: Webhook received successfully
# Links (connect response fields to other operations):
paths:
/orders:
post:
responses:
"201":
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
links:
GetOrderById:
operationId: getOrder
parameters:
orderId: "$response.body#/id" # use the id from the response
# Nullable types (3.1 syntax vs 3.0):
# OpenAPI 3.0: {type: string, nullable: true}
# OpenAPI 3.1: {type: [string, "null"]}
# Or use oneOf for complex nullable schemas:
schema:
oneOf:
- $ref: "#/components/schemas/User"
- type: "null"
Track OpenAPI, Swagger, and API tooling releases.
ReleaseRun monitors developer tooling and 13+ technologies.
Related: FastAPI Reference | NGINX Ingress Controller Reference | TypeScript EOL Tracker
🔍 Free tool: npm Package Health Checker — check openapi-types, swagger-ui-express, and related packages for known CVEs and active maintenance.
Founded
2023 in London, UK
Contact
hello@releaserun.com