DEV Community

Cover image for My OpenAPI changelog generator found 1,900 breaking changes — a formatter had just reordered every key
InApp
InApp

Posted on Originally published at imapp.blogspot.com

My OpenAPI changelog generator found 1,900 breaking changes — a formatter had just reordered every key

I built an OpenAPI changelog generator because API release notes are miserable to write by hand: diff two specs, get a structured list of breaking changes — removed paths, changed types, new required fields.

The first real run humbled me. I fed it two versions of a partner's spec, one release apart. It reported 1,900+ changes. The team had shipped exactly one new endpoint. Every operation, every schema, every response was flagged as modified.

The cause was a formatter, not the API. Between the two releases they'd added a YAML formatting step to CI. Object key order is semantically meaningless in OpenAPI — but my differ treated reordered keys as add/remove pairs. Parameters swapped positions, properties got alphabetized, security schemes moved. Each one produced a phantom edit.

The fix wasn't smarter diffing — it was canonicalization before diffing. Parse both specs, recursively sort object keys, sort the arrays where order doesn't matter (tags, servers, scopes, operation parameter lists), normalize $ref formatting, re-serialize, then diff the canonical forms. False positives dropped from ~1,900 to 14. All 14 were real.

The survivors taught a second lesson. One was a single-line edit to a shared Error schema under components: it gained a required field. Technically one change — except that schema is $ref'd from 47 operations, so the blast radius was nearly half the API. A changelog that says "components.Error modified" is accurate and useless. The generator now tracks referrers and lists every impacted operation per schema change.

The asymmetry stuck with me: reordering is noise you eliminate by normalizing, while indirection is impact you surface by expansion. Both are invisible in a raw spec diff.

I packaged the canonicalizing differ as the OpenAPI Changelog Generator API at https://x402.freeq.one/tools/changelog_openapi.html — give it a base spec and the new spec, and it returns machine- and human-readable changes with the noise pre-filtered. The boring lesson generalizes: any diff tool operating on serialized files instead of semantic models will lie the first time someone runs prettier.

Top comments (0)