OpenAPI Specification — The Complete Guide to Designing, Documenting, and Generating APIs
What is OpenAPI?#
OpenAPI is a standard for describing REST APIs in a machine-readable format. You write a YAML or JSON file that defines every endpoint, request body, response, and authentication method. Then tools generate documentation, client SDKs, server stubs, and validation middleware automatically.
OpenAPI 3.1 (the current version) is fully compatible with JSON Schema, making it the most powerful version yet.
Why OpenAPI matters#
Without a specification, API knowledge lives in developers' heads, in scattered Notion docs, or in outdated Postman collections. OpenAPI fixes this:
- Single source of truth — one file describes the entire API
- Auto-generated docs — always up to date, never stale
- Client generation — SDKs in any language from one spec
- Contract testing — validate requests and responses against the spec
- Design-first workflow — agree on the API before writing code
OpenAPI 3.1 document structure#
Every OpenAPI document has these top-level sections:
openapi: "3.1.0"
info:
title: My API
version: "1.0.0"
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: List users
responses:
"200":
description: Success
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
Key sections explained#
| Section | Purpose |
|---|---|
openapi | Spec version (always "3.1.0" for latest) |
info | API name, version, description, contact, license |
servers | Base URLs for different environments |
paths | Every endpoint and its operations |
components | Reusable schemas, parameters, responses, security schemes |
security | Global authentication requirements |
tags | Logical grouping for documentation |
Path operations#
Path operations define what each endpoint does. Every HTTP method (GET, POST, PUT, PATCH, DELETE) can have its own operation.
A complete path operation#
paths:
/users/{userId}:
get:
operationId: getUser
summary: Get a user by ID
tags:
- Users
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: User found
content:
application/json:
schema:
$ref: "#/components/schemas/User"
"404":
description: User not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Parameter types#
- path —
/users/{userId}— part of the URL - query —
/users?status=active— after the question mark - header —
X-Request-ID: abc123— in the request headers - cookie —
session=xyz— in cookies
Schema definitions#
Schemas define the shape of your data. OpenAPI 3.1 uses full JSON Schema, giving you powerful validation.
Common patterns#
components:
schemas:
User:
type: object
required:
- id
- email
properties:
id:
type: string
format: uuid
readOnly: true
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 200
role:
type: string
enum: [admin, member, viewer]
default: viewer
createdAt:
type: string
format: date-time
readOnly: true
Composition with allOf, oneOf, anyOf#
# Inheritance pattern
AdminUser:
allOf:
- $ref: "#/components/schemas/User"
- type: object
properties:
permissions:
type: array
items:
type: string
# Discriminated union
Event:
oneOf:
- $ref: "#/components/schemas/ClickEvent"
- $ref: "#/components/schemas/PageViewEvent"
discriminator:
propertyName: eventType
Components and reusability#
The components section is where you define reusable pieces. This avoids duplication and keeps your spec DRY.
Reusable components#
- schemas — data models (User, Error, PaginatedResponse)
- parameters — shared query/header params (pagination, API version)
- responses — common responses (401 Unauthorized, 429 Rate Limited)
- requestBodies — shared request bodies
- headers — common response headers (X-RateLimit-Remaining)
- securitySchemes — authentication methods
Example: reusable pagination#
components:
parameters:
PageParam:
name: page
in: query
schema:
type: integer
minimum: 1
default: 1
PageSizeParam:
name: pageSize
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
schemas:
PaginationMeta:
type: object
properties:
page:
type: integer
pageSize:
type: integer
totalItems:
type: integer
totalPages:
type: integer
Security schemes#
OpenAPI supports multiple authentication methods. Define them in components and apply them globally or per-operation.
Common security schemes#
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read:users: Read user data
write:users: Modify user data
# Apply globally
security:
- BearerAuth: []
Per-operation override#
paths:
/public/health:
get:
security: [] # No auth required
/admin/users:
delete:
security:
- OAuth2: [write:users] # Requires specific scope
Code generation#
One of OpenAPI's greatest strengths is code generation. Write the spec once, generate code for every platform.
Client generation#
- openapi-generator — supports 50+ languages (TypeScript, Python, Go, Java, Rust, Swift)
- openapi-typescript — generates TypeScript types from OpenAPI specs
- Kiota (Microsoft) — generates API clients with built-in auth handling
- Orval — generates React Query/SWR hooks from OpenAPI
Server generation#
- openapi-generator — generates server stubs for Express, FastAPI, Spring Boot
- Hono — OpenAPI-first framework for TypeScript
- FastAPI — Python framework that generates OpenAPI from code (reverse direction)
What gets generated#
| Artifact | Use case |
|---|---|
| TypeScript types | Frontend type safety |
| API client class | HTTP calls with proper types |
| Validation middleware | Request/response validation on the server |
| Mock server | Frontend development without a backend |
| Test cases | Contract testing from the spec |
Validation#
Validate your OpenAPI spec and validate API traffic against it.
Spec validation#
- Spectral (Stoplight) — linting rules for OpenAPI documents
- openapi-spec-validator — checks structural correctness
- Vacuum — fast OpenAPI linting with 200+ rules
Runtime validation#
- express-openapi-validator — validate Express requests/responses against your spec
- committee (Ruby) — request/response validation middleware
- connexion (Python) — Flask-based framework with built-in OpenAPI validation
Custom linting rules with Spectral#
# .spectral.yml
extends: spectral:oas
rules:
operation-operationId:
severity: error
message: Every operation must have an operationId
path-must-have-tags:
severity: warn
given: "$.paths.*.*"
then:
field: tags
function: truthy
Tools for working with OpenAPI#
Documentation tools#
- Swagger UI — the original interactive API docs (try-it-out feature)
- Redoc — clean, three-panel documentation layout
- Stoplight Elements — modern, customizable API docs component
- Scalar — beautiful, fast API reference docs
Design tools#
- Stoplight Studio — visual OpenAPI editor with Git integration
- Swagger Editor — browser-based YAML editor with live preview
- Insomnia — API client with OpenAPI design mode
Testing tools#
- Dredd — test your API against the spec automatically
- Schemathesis — property-based testing generated from OpenAPI
- Prism (Stoplight) — mock server and validation proxy
Design-first vs code-first#
Design-first (recommended for teams)#
- Write the OpenAPI spec collaboratively
- Review the spec in a PR (it is just YAML)
- Generate server stubs and client SDKs
- Implement the server logic
- Validate in CI that the implementation matches the spec
Code-first (faster for solo developers)#
- Write your API code with annotations or decorators
- Generate the OpenAPI spec from the code
- Use the generated spec for docs and client generation
When to choose which#
| Factor | Design-first | Code-first |
|---|---|---|
| Team size | Large teams | Solo or small teams |
| API consumers | External or cross-team | Internal only |
| Change management | Spec review in PRs | Code review covers it |
| Frontend development | Can start before backend | Must wait for backend |
Best practices#
- Use operationId on every operation — code generators need it for method names
- Version your API in the URL —
/v1/usersnot header-based versioning - Define error schemas — consistent error responses across all endpoints
- Use $ref everywhere — avoid inline schemas, keep everything in components
- Add examples — real examples make documentation 10x more useful
- Lint in CI — run Spectral on every PR to catch spec issues early
- Keep the spec in Git — treat it as code, review changes in PRs
Explore API architectures on Codelit#
On Codelit, generate any API architecture and see how API gateways, authentication flows, and microservice communication patterns connect. Visualize your OpenAPI-driven workflow from client to database.
Article #432 in the Codelit engineering series. Explore our full library of system design, infrastructure, and architecture guides at codelit.io.
Try it on Codelit
GitHub Integration
Paste any repo URL to generate an interactive architecture diagram from real code
Related articles
API Backward Compatibility: Ship Changes Without Breaking Consumers
6 min read
api designBatch API Endpoints — Patterns for Bulk Operations, Partial Success, and Idempotency
8 min read
system designCircuit Breaker Implementation — State Machine, Failure Counting, Fallbacks, and Resilience4j
7 min read
Try these templates
Build this architecture
Generate an interactive architecture for OpenAPI Specification in seconds.
Try it in Codelit →
Comments