OpenAPI Specification Files: Designing and Documenting REST APIs
The OpenAPI Specification (OAS), formerly known as Swagger, is the industry standard for describing REST APIs. An OpenAPI file — typically saved as openapi.yaml, swagger.json, or api.yaml — defines every endpoint, request parameter, response schema, authentication method, and error code in a machine-readable format. From a single specification file, teams can generate interactive documentation, client SDKs in dozens of languages, server stubs, test suites, and mocks — all automatically.
Brief History
The Swagger specification was created by Tony Tam at Wordnik around 2011 to solve a problem every API team faced: keeping documentation in sync with the actual API implementation. In 2015, Swagger was donated to the OpenAPI Initiative (part of the Linux Foundation) and renamed OpenAPI Specification. OpenAPI 2.0 was the first version under the new name; OpenAPI 3.0 (released 2017) overhauled the request body handling and component system. OpenAPI 3.1 (2021) aligned the specification with JSON Schema 2020-12, resolving years of compatibility friction.
File Format and Structure
OpenAPI files are valid JSON or YAML. YAML is strongly preferred for human authoring because it supports comments and avoids JSON's bracket noise.
Top-Level Structure (OpenAPI 3.1)
openapi: 3.1.0
info:
title: KaijuConverter API
description: File conversion API with format detection and async job queuing
version: 2.0.0
contact:
name: API Support
email: api@kaijuconverter.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.kaijuconverter.com/v2
description: Production server
- url: https://sandbox.kaijuconverter.com/v2
description: Sandbox for testing
paths:
/convert:
post:
summary: Submit a conversion job
operationId: createConversionJob
tags: [Conversions]
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/ConversionRequest'
responses:
'202':
description: Job accepted
content:
application/json:
schema:
$ref: '#/components/schemas/Job'
'400':
$ref: '#/components/responses/BadRequest'
'413':
description: File too large (max 25 MB)
security:
- ApiKeyAuth: []
Paths and Operations
Each path in the paths object contains one or more HTTP operations (get, post, put, patch, delete, head, options, trace). Every operation should have:
summary— short description (shown in navigation)description— detailed explanation (supports Markdown)operationId— unique camelCase identifier (used by code generators)tags— groups operations for documentation organizationparameters— query, path, header, and cookie parametersrequestBody— request payload schemaresponses— keyed by HTTP status code
Parameters
parameters:
- name: jobId
in: path
required: true
description: The conversion job identifier
schema:
type: string
format: uuid
example: "3fa85f64-5717-4562-b3fc-2c963f66afa6"
- name: format
in: query
required: false
schema:
type: string
enum: [json, xml]
default: json
- name: X-Api-Version
in: header
schema:
type: string
example: "2024-01"
Components: Reusable Schemas
The components section stores reusable definitions referenced with $ref:
components:
schemas:
Job:
type: object
required: [id, status, createdAt]
properties:
id:
type: string
format: uuid
status:
type: string
enum: [pending, processing, completed, failed]
progress:
type: integer
minimum: 0
maximum: 100
resultUrl:
type: string
format: uri
nullable: true
createdAt:
type: string
format: date-time
error:
$ref: '#/components/schemas/ApiError'
ApiError:
type: object
required: [code, message]
properties:
code:
type: string
example: "UNSUPPORTED_FORMAT"
message:
type: string
details:
type: array
items:
type: string
responses:
BadRequest:
description: Invalid request parameters
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-Api-Key
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.kaijuconverter.com/authorize
tokenUrl: https://auth.kaijuconverter.com/token
scopes:
convert:read: Read conversion jobs
convert:write: Submit new conversions
OpenAPI 2.0 vs 3.0 vs 3.1
OpenAPI 2.0 (Swagger): Uses swagger: '2.0', has basePath and host instead of servers, uses definitions instead of components/schemas. Request bodies are defined with in: body parameters. Still widely supported by older tools.
OpenAPI 3.0: Introduced servers, moved request bodies to requestBody, renamed definitions to components/schemas, added oneOf/anyOf/allOf/not. Broke compatibility with Swagger 2.0.
OpenAPI 3.1: Full JSON Schema 2020-12 compatibility. Allows $schema keywords, webhook support (webhooks object), and type as an array (type: [string, null] instead of nullable: true). Most tools now support 3.1.
Tooling Ecosystem
Documentation:
- Swagger UI — interactive browser-based documentation, served at
/api-docs - Redoc — polished single-page documentation, popular for public APIs
- Stoplight Elements — embeddable documentation component
Code Generation:
- openapi-generator — generates clients in 50+ languages and server stubs in 20+ frameworks
- swagger-codegen — the original generator, now mostly superseded by openapi-generator
- oapi-codegen — Go-specific, generates idiomatic Go code
Validation and Linting:
- Spectral — highly configurable linter with built-in ruleset and custom rule support
- openapi-cli — bundles, validates, and lints OpenAPI files
- vacuum — blazing-fast Spectral-compatible linter written in Go
Mocking:
- Prism — runs a mock server from an OpenAPI file, validates request/response contracts
- WireMock — supports OpenAPI import for stubbing
Testing:
- Schemathesis — property-based API testing from OpenAPI schemas, finds edge cases automatically
- Dredd — validates a running API against its OpenAPI specification
Generating OpenAPI from Code
Most web frameworks offer libraries that auto-generate OpenAPI specifications from code annotations:
- FastAPI (Python) — generates OpenAPI 3.1 automatically from function type hints
- Springdoc (Java/Spring Boot) — scans
@RestControllerannotations - tsoa (TypeScript/Node.js) — generates from TypeScript decorators
- go-swagger (Go) — parses Swagger comments in Go source
- NestJS (
@nestjs/swagger) — decorator-based generation for NestJS
This code-first approach keeps the specification in sync with the implementation but can produce verbose or poorly documented schemas without careful annotation.
File Management and Multi-File Schemas
Large API specifications benefit from splitting into multiple files linked via $ref:
# openapi.yaml (root)
paths:
/users:
$ref: './paths/users.yaml'
/jobs:
$ref: './paths/jobs.yaml'
components:
schemas:
Job:
$ref: './schemas/job.yaml'
Tools like redocly bundle and openapi-cli bundle resolve all $ref pointers and produce a single self-contained output file for distribution.
Best Practices
Write descriptions for everything: Every operation, parameter, schema property, and enum value should have a description. These descriptions appear in generated docs and client SDK docstrings.
Use operationId consistently: Generators use operationId as function/method names. Use camelCase verbs: createUser, listOrders, deleteComment.
Version via URL, not headers: /v1/users is universally supported; header-based versioning confuses OpenAPI tooling.
Define error responses explicitly: Enumerate all possible error codes (400, 401, 403, 404, 422, 429, 500) with schemas. Undocumented error codes confuse API consumers.
Use $ref aggressively: Duplicated schemas drift out of sync. Centralize in components and reference everywhere.
Validate in CI: Run Spectral or openapi-cli in your CI pipeline to catch breaking changes before they reach production. A breaking change warning on main is far cheaper to fix than a broken client integration discovered post-deployment.
Related conversions
Frequent conversions across the catalogue: