What Are Breaking Changes and How Do You Avoid Them?

Posted in

One of the trickiest aspects of being a software provider is managing change. On the one hand, you want to continually evolve your offering, adding new features, and improving old ones to maintain your competitive edge. On the other hand, you know that continuity is paramount to your developers, so changes should have minimal impact on existing integrations.

In any case, something you definitely want to watch out for is breaking change, which can cause your clients’ applications to fail. Especially in the world of API connections, breaking change is a significant concern. So, what exactly constitutes breaking change in terms of web APIs? And how can we avoid it?

What Is a Breaking Change?

As the name might suggest, a breaking change to an API is any change that can break a client’s application. Usually, breaking changes involve modifying or deleting existing parts of an API.

With the latter, deletion, it’s inevitable that applications break. If a client is consuming the deleted resource, field, or structure, parts of their application will cease to function. The extent to which this really “breaks” the application can vary greatly, from having a minor cosmetic effect to making the application entirely unusable; regardless, deletion is still considered a breaking change.

Modification is less likely to break applications. Even if a client is using the resource, field, or endpoint that is modified, there’s a chance their application will continue to work as normal, depending on the implementation. For example, if a multimedia API goes from returning JPEGs to PNGs, applications that save those file types as well will most likely continue to work.

Of course, modification still carries a genuine risk of breaking client applications. Since the responsible API owner doesn’t leave these things to chance, modifications should also be treated as breaking changes.

Examples

Common examples of breaking changes include:

  • Deleting a resource or method
  • Deleting a response field
  • Modifying a resource or method URI
  • Modifying a field name
  • Modifying required query parameters
  • Modifying authorization
  • Modifying rate-limiting

What Isn’t a Breaking Change?

Now that we’ve discussed what a breaking change is, you might be wondering what it isn’t. Thankfully, the answer is pretty straightforward:

In most cases, a change that adds to an API is not a breaking change.

This type of change, called an additive change, may involve new resources or methods, new response fields, and even new query parameters. Since these changes don’t affect existing flows, they shouldn’t break applications — but more on that in a second.

Examples

Common examples of additive, non-breaking changes include:

  • Adding a resource or method
  • Adding a response field
  • Adding optional query parameters

When Additive Changes Break Applications

As with every great rule, the idea that additive changes can’t break applications has its exceptions.

First and foremost, adding requirements to your API — like mandatory security schemes or required query parameters — is a breaking change. To avoid this, make sure that interacting with any additions you introduce is optional.

Even then, there are situations where API owners can add and still break their clients’ applications — especially if those applications are poorly coded. See these examples from engineer and blogger Ben Nadel:

“What if the consumer needs to serialize the data and store it in a database column that has a constrained character size? In such a case, even an ‘additive’ change could cause an unexpected database truncation error…. Or, imagine that the response was being logged to a file. An increase in the response payload size could change the velocity with which log files take up disk-space. This, in turn, could cause issues if the log files aren’t being rotated quickly enough.”

There are plenty of other scenarios where additional data can cause applications to break. Sometimes this may involve pagination, which the consumer doesn’t expect; other times, it may involve increased response times affecting the flow of an application.

Best Practices for Breaking Changes

If you want to take the best possible care of your clients (and you should!), there are quite a few best practices you can adopt to avoid and mitigate breaking changes. Let’s start with how you can avoid them, since this is always preferable for developers:

  1. Test your code for accidental breaking changes. Breaking changes are particularly troublesome if you don’t know they’re there. Thankfully, there’s an easy solution for API owners that build against an OpenAPI specification: openapi-diff. This open-source tool compares two OpenAPI (v3) specifications and alerts you if any (obvious) breaking changes have been made.
  2. Future-proof your documentation. It might be cliché, but documentation really can help you avoid breaking changes — especially additive ones. For example, in the early stages of a platform, some objects may consist of just a few fields. If you know considerably more fields will be added in the future, you can instruct clients to expect this and build their applications against it.
  3. Carefully plan your API in advance. Once again, it might be obvious, but the importance of carefully planning your APIs cannot be understated. Even something as mundane as naming can result in breaking changes — or a persistently bad developer experience — if poorly planned.

Unfortunately, there are often situations where your only option is to introduce breaking changes. If so, you should include these changes in a new version of your API while continuing to provide support for the previous version for a set period of time (usually a year). To reduce the impact versioning has on clients, you can do a few things:

  1. Use deprecation headers. To give clients just that little bit more time to react, you can deprecate features before entirely removing or overhauling them. Be sure to include this information in the deprecation HTTP header field, and know that the following two best practices still apply.
  2. Set clear timelines. To minimize confusion and encourage action, be sure to set clear timelines for when new versions will be released and when old versions will no longer be supported. You can still offer some leniency when important dates roll around, but developers don’t need to know that!
  3. Have clear notices. New versions (and deprecations) are only helpful if clients know about them, so don’t be afraid to make yourself heard. Place clear, bold notices in your developer portal — especially on documentation pages — and email developers with to-the-point subject lines.

Breaking Change Breaks Hearts

Breaking changes usually occur when you change or remove existing functionality, but they can even appear when you add to your API. In any case, breaking changes should be avoided wherever possible since they can cause significant disruption to your clients. Thankfully, there are a few best practices that can help you avoid breaking changes — or, if necessary, mitigate their impact.

What constitutes a breaking change in your mind? What does your team do to avoid breaking change? Let us know your thoughts below!