How-to guidesCatch breaking changes in CI

Catch breaking changes in CI

A breaking change is one that makes a working client fail: a removed operation, a new required parameter, a response field that went away. This guide makes apigenie diff stop such changes in pull requests, shows how to remove things without breaking anyone, and builds a changelog from the history of the file. It uses an OpenAPI file, openapi.yaml; Swagger 2.0, AsyncAPI, Protobuf and GraphQL files are compared the same way, each by what its clients depend on.

You need the CLI installed; the Quickstart shows how.

Compare two versions

apigenie diff takes the version clients use today and the new one:

git show main:openapi.yaml > main.yaml
apigenie diff main.yaml openapi.yaml

Every change is rated breaking, non-breaking or non-functional (a description, an example). The command exits with status 1 when any change is breaking, so a script or a CI job can stop there. --report picks what it prints: changelog (the default), status (one word) or detailed (every property that changed); --formatter writes it as JSON, Markdown, HTML or a format editors understand.

Both files must be of the same standard. Here is the report for two versions of a Protobuf file:

shop.proto
  19  1      breaking  Modified message 'Customer'
  19  1  non-breaking    Removed field 'fax'
  25  3      breaking    Modified field 'full_name'
  25  3      breaking      Modified field name

Check every pull request

The GitHub Action compares each file with its version at the base of the pull request and shows the changes as annotations:

on: pull_request
jobs:
  api:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: mykulyak/api-genie-action@v0
        with:
          command: diff
          files: api/openapi.yaml

The step fails on breaking changes. Set base to compare with another branch or tag, such as the last release, and fail-on: never to report without failing.

A failing step only blocks the merge once the check is required. In the repository’s settings, under Branches, add a branch protection rule for the base branch (or a ruleset under Rules), turn on Require status checks to pass before merging and pick the api job. From then on a pull request with a breaking change waits until the change is withdrawn, or its severity is reconsidered.

Decide what breaks your clients

The recommended rules fit most APIs. When yours differ, change them in apigenie.yaml: each property of each kind of node takes a severity (breaking, non_breaking, non_functional or none), or one each for add, remove and modify. List recommended in extends to change only some of its rules:

version: '1.0'
commands:
  diff:
    extends: [recommended]
    rules:
      operation:
        tags: none

The diff configuration lists the node types and their properties, and how to set different rules for requests and responses.

Retire an operation on a schedule

Removing an operation is breaking, unless clients were told in advance. Deprecate it with a sunset date first, and ship that: deprecating is not breaking.

paths:
  /v1/orders:
    get:
      deprecated: true
      x-sunset: 2027-01-31

Once the date has passed, the recommended rules treat the removal as non-breaking, and the same CI job lets it through. --today sets the date of the comparison, to try it out before then.

For changes bigger than one operation, apigenie evolve plan does the planning. It takes the document clients use and the one you want, and writes an expand wave (the new shape next to the old one, deprecated, safe to ship now) and a contract wave (the target, to ship after the sunset):

apigenie evolve plan main.yaml openapi.yaml --out evolve-out/

evolve is experimental; see evolve for its recipes.

Set the version and keep a changelog

--update-version writes the smallest info.version the changes allow, a new major version for breaking changes, minor for non-breaking and patch for non-functional ones, and keeps the rest of the file as it is:

apigenie diff main.yaml openapi.yaml --update-version

apigenie changelog compares the committed versions of a file and describes what changed for clients, per commit or per release tag:

apigenie changelog openapi.yaml --revisions tags --tag-pattern 'v*' --unreleased

Next steps

  • diff: every option, the rules of each standard and the JSON report.
  • changelog: revisions, tags and output formats.
  • Publish API documentation: the changelog of each API on its documentation site.