🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Build an AI API Contract Breaking Change Detector with Claude API

OpenAPI schema diff tools flag every field change equally, drowning real breaking changes in noise from additive, backward-compatible ones. Build a tool that uses Claude API to reason about which schema changes actually break existing consumers.

Shubham4 min read
Share:Tweet

Standard OpenAPI diff tools report every schema change as a flat list — a new optional field and a removed required field show up with the same visual weight, even though one is completely safe and the other breaks every existing client. This tool reasons about actual consumer impact, not just schema delta.

Setup

bash
pip install anthropic pyyaml deepdiff

Schema Diff Extraction

python
import yaml
import anthropic
from deepdiff import DeepDiff
 
client = anthropic.Anthropic()
 
 
def load_openapi_spec(path: str) -> dict:
    with open(path) as f:
        return yaml.safe_load(f)
 
 
def get_raw_diff(old_spec: dict, new_spec: dict) -> dict:
    """Get the structural diff — this is the raw material, not the final answer."""
    diff = DeepDiff(old_spec, new_spec, ignore_order=True)
    return diff.to_dict()

Breaking Change Classification

python
CLASSIFY_PROMPT = """Analyze this OpenAPI schema diff and classify each
change by actual impact on existing API consumers.
 
Raw schema diff:
{raw_diff}
 
Old spec (relevant excerpt): {old_spec_excerpt}
New spec (relevant excerpt): {new_spec_excerpt}
 
Classify each individual change as:
- BREAKING: will cause existing client code to fail (removed field,
  removed endpoint, type change on existing field, new required field
  with no default, narrowed enum values, changed error response codes)
- SAFE: backward compatible (new optional field, new endpoint, widened
  enum values, new optional query parameter, relaxed validation)
- NEEDS_REVIEW: ambiguous impact depending on how strictly consumers
  validate responses (e.g. reordered fields in a response usually safe,
  but a consumer doing strict schema validation could break)
 
For each BREAKING change, explain specifically which client code pattern
would fail and why.
 
Respond with ONLY valid JSON:
{{"changes": [
  {{"path": "...", "classification": "BREAKING"|"SAFE"|"NEEDS_REVIEW",
    "explanation": "..."}}
], "overall_verdict": "safe_to_release" | "breaking_changes_present"}}"""
 
 
def classify_changes(raw_diff: dict, old_spec: dict, new_spec: dict) -> dict:
    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=2500,
        messages=[{
            "role": "user",
            "content": CLASSIFY_PROMPT.format(
                raw_diff=raw_diff,
                old_spec_excerpt=str(old_spec)[:2000],
                new_spec_excerpt=str(new_spec)[:2000],
            )
        }]
    )
    text = response.content[0].text.strip()
    if text.startswith("```"):
        text = text.split("```")[1].replace("json", "", 1).strip()
    import json
    return json.loads(text)

Example Output

API Contract Analysis: orders-api v2.3.0 -> v2.4.0

BREAKING (2):
- paths./orders/{id}.get.responses.200.schema.properties.status
  Old: enum ["pending", "shipped", "delivered"]
  New: enum ["pending", "processing", "shipped", "delivered"]
  This is actually SAFE for consumers reading the enum, but BREAKING
  for any consumer with a switch/case that has no default branch —
  flagging as NEEDS_REVIEW rather than a hard break, since impact
  depends on client implementation style, not the schema alone.

- paths./orders.post.requestBody.schema.required
  Old: ["customer_id", "items"]
  New: ["customer_id", "items", "shipping_address"]
  BREAKING: any existing client not sending shipping_address will now
  get a 400 on order creation. This requires either a client-side
  update before this ships, or making the field optional with a
  sensible default/fallback server-side.

SAFE (4):
- New optional field "gift_message" on the order request — additive, safe
- New endpoint GET /orders/{id}/tracking — additive, safe
- New optional response field "estimated_delivery" — additive, safe
- Relaxed max_length on customer notes field (200 -> 500) — safe, widening

Verdict: BREAKING CHANGES PRESENT — do not release as a minor version.
Either revert the required field addition or bump to v3.0.0 with a
deprecation notice period for v2 clients.

CI Integration — Gate Releases on Breaking Changes

yaml
# .github/workflows/api-contract-check.yml
name: API Contract Check
on:
  pull_request:
    paths: ["openapi.yaml"]
 
jobs:
  contract-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: git show origin/main:openapi.yaml > old-spec.yaml
      - run: python contract_check.py --old old-spec.yaml --new openapi.yaml
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      # Script exits non-zero if overall_verdict is "breaking_changes_present"
      # AND the PR is targeting a version that shouldn't have breaking changes

Why Reasoning Beats a Pure Diff Tool Here

A structural diff tool correctly identifies that something changed but has no concept of API semantics — it can't distinguish "added a field with a sensible default that's genuinely safe" from "added a required field that breaks every existing caller," because both look identical at the schema-diff level (a new key appeared under required). The reasoning step is specifically what turns a noisy diff into an actionable breaking-change report a reviewer can trust without re-verifying every line themselves.


More AI DevOps tooling? Read our Build AI YAML diff explainer with Claude API and Build AI synthetic test generator with Claude API.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Build an AI Feature Flag Risk Analyzer with Claude API

Feature flags accumulate silently until nobody remembers what half of them do or whether they're safe to remove. Build a tool that analyzes your feature flag inventory against actual usage and code references with Claude API to flag stale, risky, or safe-to-delete flags.

S
4 min readRead

Comments