OneEnv
← All posts💥 Concept

How API Breaking Changes Affect Downstream Services

ShareLinkedInX

An API change is breaking when some existing caller stops working without being changed. The difficulty in a distributed system is not recognising a breaking change in the abstract; it is knowing who the callers are. This article covers what counts as breaking, how teams make changes safely, and what tooling can and cannot tell you.

What counts as breaking

  • Removing or renaming a route, field or enum value.
  • Changing the method or the path shape (/invoices/{id} to /invoices/by-id/{id}).
  • Making an optional request field required, or tightening its validation (a stricter regex, a shorter max length).
  • Changing a field's type or the meaning of its value.
  • Changing error behaviour callers depend on, such as status codes.

Adding an optional request field or a new response field is usually safe, unless a strict client rejects unknown fields. 'Usually' is doing real work in that sentence.

A scenario

billing exposes GET /v1/invoices. web calls it directly, mobile-bff proxies it, and a partner script calls it from outside. Renaming the path to /v2/invoices breaks all three. Only the first two are in your repositories; the third is invisible to any code search.

How teams change contracts safely

  • Expand, then contract. Serve old and new for a period, move callers, then remove the old.
  • Version the surface. Put breaking changes behind a new version and deprecate the old, with a published sunset date.
  • Consumer-driven contract tests. Callers publish what they rely on, and the provider's build fails if a change violates it. Tools such as Pact do this; it is the strongest option for callers you control.
  • Schema diffing in CI. Compare OpenAPI documents between commits and fail on removals or type changes.
  • Telemetry. Count calls per route and caller before removing anything.
Illustrative CI step: fail on breaking OpenAPI changes (verify the tool and flags for your setup)
# using the openapi-diff style of tools
openapi-diff openapi.main.yaml openapi.pr.yaml --fail-on-incompatible

The consumer-discovery problem

All of the above assume you know the callers. In practice a registry of 'who calls what' is either missing or stale. Traffic telemetry finds real callers but only after the fact; static analysis finds repository callers but misses everything outside them; a hand-maintained list rots. Most teams end up combining a recorded consumer list with telemetry.

Trade-offs

  • Dual-serving costs maintenance and testing for as long as both exist.
  • Contract tests need callers to participate; they do not help with external clients.
  • A recorded consumer list is only as good as its upkeep.
Where OneEnv fits (and where it does not)
OneEnv lets a service own an API route, lets other services record that they inherit it or track it as a source, and stages route changes on a branch. When the branch merges, each recorded consumer gets a decision, and a method change, path-shape change or deletion is flagged as breaking in the impact score. It does not read your code, watch your traffic, or run contract tests, so it only knows the consumers someone recorded. Use it to keep the consumer list honest and the decision visible, and keep your contract tests and telemetry. Details: API contract management.
ShareLinkedInX