Evolving APIs

APIs are contracts between clients and servers. Backward-incompatible changes to APIs can cause unexpected errors for clients of the service. In a microservices architecture, precautions have to be taken to ensure that changes to a service's API do not unintentionally cause cascading problems throughout the system.

A popular approach is to version your API, either through the URL or via content negotiation in request headers. Because they're generally easier to work with, and often easier to cache, URL prefixes or query strings tend to be more common—in this case, the API endpoint is either prefixed with a version string (that is, /v1/users) or called with a query string parameter specifying a version or even a date (that is, /v1/users?version=1.0 or /v1/users?version=20180122).

With edge proxies or service mesh configurations, it's even possible to run multiple versions of software in an environment and route requests based on the URL to older or newer versions of a service. This changes the traditional life cycle of a serviceyou can safely decommission a version when it is no longer receiving any traffic. This can be useful, especially in the case of a public API where you have little control over clients.

Microservices are different than public APIs. The contract between clients and the server in a public API is much more long-lived. In a microservices architecture, it's easier to track down clients who are using your service and convince them to upgrade their code! Nevertheless, API versioning is sometimes necessary. Because being able to respond successfully to multiple versions of an API is a maintenance burden, we'd like to avoid it for as long as possible. To do this, there are a few practices that can be used to avoid making backward-incompatible changes.