
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
api-schema-diff
Advanced tools
Detect breaking changes between API schemas (OpenAPI / JSON Schema) in a deterministic, CI-friendly way.
api-schema-diff is a CLI tool designed to answer one question reliably:
"Will this schema change break existing clients?"
API changes often break clients silently.
Common causes:
api-schema-diff catches these issues before they reach production.
pip install api-schema-diff
Or install from source:
git clone https://github.com/teolzr/schema-diff.git
cd schema-diff
pip install -e .
Requirements:
typer>=0.12rich>=13.7Run without installing Python:
# Pull the image
docker pull ghcr.io/teolzr/schema-diff:latest
# Run with local files
docker run --rm -v $(pwd):/workspace ghcr.io/teolzr/schema-diff:latest old.yaml new.yaml
# Check version
docker run --rm ghcr.io/teolzr/schema-diff:latest --version
# Use in CI/CD
docker run --rm \
-v $(pwd):/workspace \
ghcr.io/teolzr/schema-diff:latest \
schemas/v1.yaml schemas/v2.yaml \
--format json
Available tags:
latest - Latest stable releasev0.1.4 - Specific versionmain - Latest from main branchUse in any GitHub workflow:
- uses: teolzr/schema-diff@v1
with:
old: api/schema-v1.yaml
new: api/schema-v2.yaml
Compare against main branch:
- run: git show origin/main:api/schema.yaml > /tmp/baseline.yaml
- uses: teolzr/schema-diff@v1
with:
old: /tmp/baseline.yaml
new: api/schema.yaml
JSON output:
- uses: teolzr/schema-diff@v1
with:
old: old.yaml
new: new.yaml
format: json
fail-on-breaking: false
api-schema-diff old.json new.json
Exit codes:
0 → No breaking changes found1 → Breaking changes detectedText output (default):
api-schema-diff old.json new.json
Output:
BREAKING CHANGES FOUND
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Type ┃ Path ┃ Old Type┃ New Type┃ Message ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
│ removed_field│ User.email │ │ │ │
│ type_change │ Order.amount│ <number>│ <string>│ │
└──────────────┴─────────────┴─────────┴─────────┴───────────────────────┘
JSON output:
api-schema-diff old.json new.json --format json
Output:
{
"breaking": [
{
"type": "removed_field",
"severity": "breaking",
"path": "User.email",
"old_type": null,
"new_type": null,
"message": null
},
{
"type": "type_change",
"severity": "breaking",
"path": "Order.amount",
"old_type": "<number>",
"new_type": "<string>",
"message": null
}
],
"non_breaking": []
}
api-schema-diff [OPTIONS] OLD_FILE NEW_FILE
Arguments:
OLD_FILE - Path to the old schema file (JSON or YAML)NEW_FILE - Path to the new schema file (JSON or YAML)Options:
--format [text|json] - Output format (default: text)--fail-on-breaking / --no-fail-on-breaking - Exit with code 1 when breaking changes are found (default: true)--help - Show help messageUse --no-fail-on-breaking to always exit with code 0 (useful for reporting without failing CI):
api-schema-diff old.json new.json --no-fail-on-breaking
old.json:
{
"User": {
"email": "a@b.com",
"age": 30
},
"Order": {
"amount": 12.5
}
}
new.json:
{
"User": {
"age": "30"
},
"Order": {
"amount": "12.5"
},
"NewThing": {}
}
api-schema-diff old.json new.json
Detected changes:
User.email field removedUser.age type changed from number to stringOrder.amount type changed from number to stringNewThing object addedold-api.yaml:
openapi: 3.0.0
paths:
/users:
get:
parameters:
- name: limit
in: query
required: false
schema:
type: integer
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
name:
type: string
email:
type: string
new-api.yaml:
openapi: 3.0.0
paths:
/users:
get:
parameters:
- name: limit
in: query
required: true # Now required!
schema:
type: integer
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
name:
type: string
# email removed!
api-schema-diff old-api.yaml new-api.yaml
Detected changes:
limit became requiredemail removedname: Schema Diff Check
on:
pull_request:
paths:
- 'api/schema.yaml'
jobs:
schema-diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install api-schema-diff
run: pip install api-schema-diff
- name: Get old schema from main branch
run: git show origin/main:api/schema.yaml > old-schema.yaml
- name: Check for breaking changes
run: api-schema-diff old-schema.yaml api/schema.yaml
api-schema-diff:
image: python:3.10
before_script:
- pip install api-schema-diff
script:
- git show origin/main:api/schema.yaml > old-schema.yaml
- api-schema-diff old-schema.yaml api/schema.yaml
only:
changes:
- api/schema.yaml
Create .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: api-schema-diff
name: Check API schema for breaking changes
entry: bash -c 'git show HEAD:api/schema.yaml > /tmp/old-schema.yaml && api-schema-diff /tmp/old-schema.yaml api/schema.yaml'
language: system
files: 'api/schema.yaml'
pass_filenames: false
# Clone the repository
git clone https://github.com/teolzr/schema-diff.git
cd schema-diff
# Install in development mode
pip install -e .
# Install development dependencies
pip install pytest pytest-cov black ruff
# Run all tests
pytest
# Run with coverage
pytest --cov=schema_diff --cov-report=html
# Run specific test file
pytest tests/test_openapi_diff.py
Note: The Python package is still named schema_diff internally, but the PyPI package and CLI command are api-schema-diff.
# Format code
black .
# Lint code
ruff check .
schema-diff/
├── schema_diff/
│ ├── __init__.py
│ ├── cli.py # CLI entry point
│ ├── diff.py # Generic JSON diff logic
│ ├── loader.py # Schema file loading
│ ├── models.py # Data models
│ ├── rules.py # Breaking change rules
│ └── openapi/
│ ├── __init__.py
│ ├── diff.py # OpenAPI-specific diff
│ ├── json_schema_diff.py # JSON Schema diffing
│ ├── normalizer.py # Schema normalization
│ └── resolver.py # $ref resolution
├── tests/
├── pyproject.toml
└── README.md
$ref references and normalizes structureBreaking changes:
Non-breaking changes:
Contributions are welcome! Please:
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)MIT License - see LICENSE file for details
Built with:
Note: Repository name is schema-diff, but PyPI package name is api-schema-diff
FAQs
Detect breaking changes between API schemas (OpenAPI / JSON Schema)
We found that api-schema-diff demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.