Lesson 23 / 27
Contract-First with OpenAPI
Describe the API in an OpenAPI document and lint and diff it automatically.
One document, many uses
An OpenAPI document (YAML or JSON) describes paths, parameters, request and response schemas, errors and security in a machine-readable form. Designing it first (contract-first) lets teams review and mock the API before implementation, and the same file then drives interactive docs, client SDK and server stub generation, request/response validation, contract tests and breaking-change checks between versions. Reuse definitions with $ref under components, give every operation a unique operationId, and describe error responses too. Keep the spec in version control next to the code and fail the build if the implementation drifts from it.
Keep the promise in code
A machine-readable contract, automated checks and shared standards keep many teams consistent.
A small OpenAPI 3.1 document
Describes the v2 list and get endpoints with a reusable Item schema, a problem+json error and a rate-limit response. I parsed it with PyYAML in the next snippet.
openapi: 3.1.0
info:
title: Items API
version: "2.0.0"
servers:
- url: https://api.example.com
paths:
/v2/items:
get:
operationId: listItems
summary: List items (cursor pagination)
parameters:
- name: limit
in: query
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
- name: cursor
in: query
schema: { type: string }
responses:
"200":
description: A page of items
content:
application/json:
schema: { $ref: "#/components/schemas/ItemPage" }
"429":
$ref: "#/components/responses/RateLimited"
/v2/items/{id}:
get:
operationId: getItem
parameters:
- name: id
in: path
required: true
schema: { type: integer }
responses:
"200":
description: One item
content:
application/json:
schema: { $ref: "#/components/schemas/Item" }
"404":
description: Not found
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
components:
schemas:
Item:
type: object
required: [id, first_name, last_name]
properties:
id: { type: integer }
first_name: { type: string }
last_name: { type: string }
plan: { type: string, enum: [free, pro] }
ItemPage:
type: object
required: [data]
properties:
data:
type: array
items: { $ref: "#/components/schemas/Item" }
next_cursor: { type: [string, "null"] }
Problem:
type: object
required: [title, status]
properties:
type: { type: string }
title: { type: string }
status: { type: integer }
detail: { type: string }
responses:
RateLimited:
description: Too many requests
headers:
Retry-After: { schema: { type: integer } }
Checking the spec structure, run
I ran this plain-Python example. Save the YAML above as openapi.yaml; this script loads it, lists the operations, checks operationId uniqueness and confirms all 5 $ref pointers resolve inside the document. It is a teaching check; real projects use dedicated validators and linters.
import yaml
spec = yaml.safe_load(open("openapi.yaml"))
ops, refs = [], []
def walk(o):
if isinstance(o, dict):
if "$ref" in o: refs.append(o["$ref"])
for v in o.values(): walk(v)
elif isinstance(o, list):
for v in o: walk(v)
walk(spec)
for path, item in spec["paths"].items():
for method, op in item.items(): ops.append((method.upper(), path, op["operationId"]))
def resolve(ref):
node = spec
for part in ref.lstrip("#/").split("/"): node = node[part]
return node
missing = [r for r in refs if not _ok(r)] if False else []
for r in refs:
try: resolve(r)
except KeyError: missing.append(r)
print(spec["openapi"], len(spec["paths"]), "paths")
print(ops)
print("unique operationIds:", len({o[2] for o in ops}) == len(ops), "| refs:", len(refs), "| unresolved:", missing)
Output:
3.1.0 2 paths
[('GET', '/v2/items', 'listItems'), ('GET', '/v2/items/{id}', 'getItem')]
unique operationIds: True | refs: 5 | unresolved: []Quick check: What is a benefit of designing the OpenAPI contract first?
- Teams can review, mock and generate code before implementing
- It removes the need for any code
- It makes APIs slower
- It prevents all bugs
Answer
Teams can review, mock and generate code before implementing — A shared, reviewable contract aligns producers and consumers early.