OpenAPI Diff — Compare API Specifications and Track Changes
In this tutorial, you will learn about OpenAPI Diff. We cover key concepts, practical examples, and best practices to help you master this topic.
OpenAPI diff tools compare two API specifications and report added, removed, and changed endpoints, models, parameters, and security schemes, enabling automated API change management.
What You'll Learn
How to use OpenAPI diff tools to compare specifications, detect breaking vs. non-breaking changes, generate human-readable changelogs, integrate diff checks in CI/CD pipelines, and manage API version evolution safely.
Why It Matters
API consumers depend on contract stability. Breaking changes without notice cause integration failures, downtime, and frustrated developers. Automated diff detection lets you review changes before deployment and communicate exactly what changed. DodaTech blocks deployments if an API diff detects breaking changes without a major version bump.
Real-World Use
A developer updates the Orders API spec to add a required field. The CI pipeline runs OpenAPI diff, flags a breaking change, and prevents the deployment. The developer reviews the diff, decides to make the field optional instead, and re-runs the pipeline.
flowchart LR
A["Current\nSpec v1"] --> C["OpenAPI\nDiff Tool"]
B["Proposed\nSpec v2"] --> C
C --> D{"Breaking\nChange?"}
D -->|"Yes"| E["Block\nDeployment"]
D -->|"No"| F["Generate\nChangelog"]
E --> G["Review &\nFix"]
G --> B
F --> H["Deploy &\nNotify"]
style C fill:#bbf7d0,stroke:#16a34a
style D fill:#fef3c7,stroke:#d97706
style E fill:#fecaca,stroke:#dc2626
Installing OpenAPI Diff
# Install openapi-diff CLI (Node.js):
npm install -g openapi-diff
echo "openapi-diff installed"
# Expected output:
# added 42 packages in 3s
# Verify installation:
openapi-diff --version
# Expected output:
# 2.0.1
# Alternative: Java-based OpenAPI Diff:
# java -jar openapi-diff.jar --help
Comparing Two Specs
# Compare two API specifications:
diff_result = """
openapi-diff spec-v1.yaml spec-v2.yaml
"""
print("Running diff...")
# Expected output:
# --- Comparing spec-v1.yaml vs spec-v2.yaml ---
#
# ## Breaking Changes
#
# ### Removed endpoints
# - DELETE /api/orders/{orderId} (endpoint removed)
#
# ### Changed endpoints
# - POST /api/orders
# * Request body: field 'email' changed from optional to required
# * Response: removed 'discount' field from 200 response
#
# ## Non-breaking Changes
#
# ### Added endpoints
# - GET /api/orders/export (new endpoint)
#
# ### Added fields
# - POST /api/orders request body: added 'notes' field (optional)
# - GET /api/orders/{orderId} response: added 'shippingDate' field
#
# --- Summary ---
# Breaking: 2
# Non-breaking: 3
Breaking vs Non-Breaking Changes
# spec-v1.yaml (original)
openapi: 3.0.3
info:
title: Orders API
version: 1.0.0
paths:
/orders:
get:
parameters:
- name: limit
in: query
schema:
type: integer
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Order'
components:
schemas:
Order:
type: object
required: [id, email]
properties:
id:
type: string
email:
type: string
status:
type: string
# spec-v2.yaml (proposed change)
# Compare with: openapi-diff spec-v1.yaml spec-v2.yaml
paths:
/orders:
get:
parameters:
- name: limit
in: query
schema:
type: integer
minimum: 1 # Added validation: non-breaking
- name: sort
in: query # Added parameter: non-breaking
schema:
type: string
components:
schemas:
Order:
type: object
required: [id, email, status] # status is now required: BREAKING
properties:
id:
type: string
email:
type: string
status:
type: string
CI/CD Integration
# .github/workflows/api-diff.yml
name: API Diff Check
on:
pull_request:
paths:
- 'specs/openapi.yaml'
jobs:
api-diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install openapi-diff
run: npm install -g openapi-diff
- name: Compare specs
run: |
git show HEAD~1:specs/openapi.yaml > spec-base.yaml
openapi-diff spec-base.yaml specs/openapi.yaml > diff-output.txt
cat diff-output.txt
- name: Check for breaking changes
run: |
if grep -q "Breaking Changes" diff-output.txt; then
echo "::error::Breaking changes detected!"
exit 1
fi
echo "No breaking changes. Proceeding."
# Expected behavior:
# - On PRs modifying the spec, runs diff against the base branch
# - Outputs the diff report
# - Fails the CI if breaking changes are found
Generating Changelogs
# Programmatic diff with openapi-diff library (Node.js):
import subprocess
import json
def generate_changelog(old_spec, new_spec, output_format="markdown"):
"""Generate a changelog from spec comparison."""
cmd = [
"openapi-diff",
old_spec,
new_spec,
"--format", output_format
]
result = subprocess.run(cmd, capture_output=True, text=True)
return result.stdout
changelog = generate_changelog(
"spec-v1.yaml",
"spec-v2.yaml",
output_format="markdown"
)
print(changelog)
# Expected output (markdown changelog):
# # API Changelog
#
# ## Breaking Changes
# - **DELETE /api/orders/{orderId}**: Endpoint removed
# - **POST /api/orders**: `email` field changed from optional to required
#
# ## Non-breaking Changes
# - **GET /api/orders/export**: New endpoint added
# - **POST /api/orders**: New optional field `notes`
Common Mistakes
1. Ignoring Breaking Changes
A seemingly small change like adding a required field to a response breaks all existing clients that parse the response. Always preserve optional fields when possible and add new fields as optional.
2. Not Running Diff in CI
Manual spec review misses subtle changes. Automated diff in CI catches every modification. Include diff checks in both PR review and deployment pipelines.
3. Misinterpreting Breaking vs Non-Breaking
Adding a new endpoint is non-breaking. Changing an existing endpoint's request or response schema often is breaking. Adding an optional field to a response is non-breaking only if clients ignore unknown fields.
4. Not Versioning Diff Results
Save diff output with each release. This creates an audit trail of API evolution and helps consumers understand what changed between versions.
5. Forgetting About Default Values
Changing a default value for a parameter appears non-breaking but changes behavior for clients that rely on the default. Semantic versioning should consider this a minor change.
Practice Questions
- What is the purpose of OpenAPI diff?
- How do you identify breaking changes in a diff result?
- Why should you run diff checks in CI/CD?
- What is the difference between breaking and non-breaking changes?
Answers:
- OpenAPI diff compares two API specifications and identifies added, removed, and changed components, classifying each change as breaking or non-breaking.
- Breaking changes are listed under the Breaking Changes section of the diff output. Key indicators: removed endpoints, changed parameter requirements, removed response fields, and added required fields.
- Automated diff checks in CI catch unexpected changes before deployment, enforce API Versioning policies, generate changelogs automatically, and prevent breaking changes from reaching consumers without review.
- Breaking changes require existing clients to update their code to continue functioning. Non-breaking changes are backward-compatible and existing clients work without modification.
Challenge: Set up a GitHub Actions workflow that runs OpenAPI diff on every PR modifying the spec, posts the diff result as a PR comment, and blocks merging if breaking changes are detected. Test it with both a breaking and non-breaking change.
FAQ
Mini Project
Take an existing API spec, introduce a breaking change (remove an endpoint, add a required field), and a non-breaking change (add an optional field, add a new endpoint). Run openapi-diff to compare, generate a markdown changelog, and verify the breaking change detection works correctly.
What's Next
Version Management — manage API specification versions and evolution.
CI/CD Codegen — integrate Code Generation with CI/CD pipelines.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro