New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

api-schema-diff

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

api-schema-diff

Detect breaking changes between API schemas (OpenAPI / JSON Schema)

pipPyPI
Version
1.0.4
Maintainers
1

api-schema-diff

PyPI version Python versions CI Docker License: MIT Code style: black

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?"

Why this exists

API changes often break clients silently.

Common causes:

  • Removing endpoints
  • Removing fields
  • Changing parameter requirements
  • Changing request/response schemas

api-schema-diff catches these issues before they reach production.

Features

Supported inputs

  • OpenAPI 3.x (JSON / YAML)
  • JSON Schema (generic structure diff)

Breaking changes detected

  • Removed paths or operations
  • Removed query / path / header parameters
  • Parameters becoming required
  • Parameter schema type changes
  • Request body removed
  • Request body becoming required
  • Request body schema breaking changes
  • Removed response status codes
  • Response schema breaking changes
  • Removed properties in schemas
  • Property type changes
  • Optional → required fields

Non-breaking changes detected

  • Added paths or operations
  • Added optional parameters
  • Added optional request bodies
  • Added response status codes
  • Added optional properties

Designed for CI

  • Deterministic output
  • Stable exit codes
  • JSON output for automation
  • Works offline (no cloud / no LLM dependency)

Installation

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:

  • Python 3.10 or higher
  • typer>=0.12
  • rich>=13.7

Docker

Run 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 release
  • v0.1.4 - Specific version
  • main - Latest from main branch

📚 Full Docker documentation →

GitHub Action

Use 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

Usage

Basic usage

api-schema-diff old.json new.json

Exit codes:

  • 0 → No breaking changes found
  • 1 → Breaking changes detected

Output formats

Text 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": []
}

CLI Options

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 message

Report-only mode

Use --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

Examples

Example 1: Generic JSON diff

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:

  • Breaking: User.email field removed
  • Breaking: User.age type changed from number to string
  • Breaking: Order.amount type changed from number to string
  • Non-breaking: NewThing object added

Example 2: OpenAPI diff

old-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:

  • Breaking: Query parameter limit became required
  • Breaking: Response property email removed

CI/CD Integration

GitHub Actions

name: 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

GitLab CI

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

Pre-commit hook

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

Development

Setup

# 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

Running tests

# 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.

Code formatting

# Format code
black .

# Lint code
ruff check .

Project structure

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

How it works

  • Schema loading: Automatically detects schema type (OpenAPI vs generic JSON/YAML)
  • Normalization: Resolves $ref references and normalizes structure
  • Diffing: Compares schemas using rule-based detection
  • Classification: Categorizes changes as breaking or non-breaking
  • Reporting: Outputs results in human-readable or JSON format

Change detection logic

Breaking changes:

  • Removing existing fields/paths → clients expect them
  • Changing types → clients may send wrong data type
  • Making optional fields required → clients may not send them
  • Removing response fields → clients may depend on them

Non-breaking changes:

  • Adding new fields/paths → clients can ignore them
  • Making required fields optional → clients can still send them
  • Adding new optional fields → backwards compatible

Roadmap

  • Support for OpenAPI 2.0 (Swagger)
  • GraphQL schema diffing
  • Custom rule configuration
  • HTML report generation
  • API compatibility scoring
  • Severity levels (error, warning, info)

Contributing

Contributions are welcome! Please:

  • Fork the repository
  • Create a feature branch (git checkout -b feature/amazing-feature)
  • Make your changes
  • Add tests for new functionality
  • Run tests and linting
  • Commit your changes (git commit -m 'Add amazing feature')
  • Push to the branch (git push origin feature/amazing-feature)
  • Open a Pull Request

License

MIT License - see LICENSE file for details

Credits

Built with:

  • Typer - CLI framework
  • Rich - Terminal formatting

Support

Note: Repository name is schema-diff, but PyPI package name is api-schema-diff

Keywords

openapi

FAQs

Did you know?

Socket

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.

Install

Related posts