What Is API Versioning
Breaking changes happen. These are changes that break the integration between your system and the consumer of your API, in other words, changes that are not backward compatible. No matter how much you try to maintain backward compatibility, sometimes requirements or architectural changes will force you to make a breaking change. So, how do you ensure there aren't any issues when changing the API? If consumers are using your API, would their changes need to be deployed simultaneously with your system? If not, the API integration will break, right?
Well, one common method of handling this is to version your API. For example, to version a register API you can provide two endpoints: /api/v1/register
and /api/v2/register
. Instead of changing the existing API called by consumers, you create a new API with the new behavior. This allows consumers to release their changes at a later date after they are done developing.
Why You Should Version Your API
The main reason to version your API is to allow for breaking changes to a specific API without disrupting existing calls from consumers.
Suppose you have an API to register a user in your system. Initially, your API only requires username
and password
to be sent by the consumer, and the user is registered successfully if there is no duplicate username in your database. After the API is released and used by consumers, there is an additional requirement to add email
as a required field. Now, to safely associate the user with the email, you'll need to require users to input an OTP sent to their email. This means the behavior of your API changes, and it will break the API integration between your system and the consumers if you release the changes.
If you want the changes to be seamless, you'll need to release the feature simultaneously for both your API and consumers, which is not ideal. It's also not good practice to force your consumers to follow your timeline.
Instead, you can version your API and allow both versions to be live simultaneously. Let's illustrate this:
Let's explore the illustration:
- Initial State: The initial state of the API has only one register API, and the consumer is using that API.
- Hosting Two APIs: Next, we provide the new version of the API at
/api/v2/register
, while the consumer continues using the oldv1
API. - Consumer Switch to Register V2: When the consumer has developed the necessary changes, they can start using the new
v2
API. - Deprecating Old API: Finally, the old
v1
API is deprecated and can no longer be accessed.
By using API versioning, you allow consumers to transition smoothly without any downtime, at their convenience.
Common Methods of API Versioning
There are four common methods to version your API. While there aren't many pros and cons for each method, you can choose the one you prefer:
API Path Versioning
API path versioning is the method used in our previous example. This approach adds the version number to the URL path. The advantage of this method is that the versioning is very explicit and visible, making it easy for people reading your API documentation to identify the version. An example is curl -X POST http://localhost/api/v1/register
.
Query Parameter Versioning
As the name suggests, query parameter versioning adds the version number as a query parameter in the URL. For example: curl -X POST http://localhost/api/register?version=1
.
Request Header Versioning
This method involves adding the version number in the request header. Unlike API Path and Query Parameter versioning, it doesn't show up in the URL, making it less obvious. Ensure you explicitly mention it in your documentation or make it a required field so your consumers are aware of it. An example of this versioning is: curl -X POST http://localhost/api/register -H "version:1"
.
Media Type Versioning
The final method is Media Type Versioning, which adds the version number in the Accept
header. While this is the cleanest method of versioning, it is the hardest to implement and identify. An example of media type versioning is as follows: curl -X POST "http://localhost/api/register" -H "Accept: application/vnd.codecurated.v1+json"
.
Communicating Changes to Consumers
The last thing I want to discuss is how to communicate these changes to your consumers. One of the main reasons for versioning your API is to reduce friction between you and the consumer when breaking changes occur.
To ensure the changes are released smoothly, make sure to:
- Update your API documentation. Properly mark the APIs that are planned for deprecation and provide guidance on the new API.
- Communicate why the changes are necessary and what could happen if the changes are not implemented.
- Inform consumers when the changes will be ready, both in the staging and production environments.
- Communicate the deprecation policies of the old API. Give consumers a reasonable amount of time to make the changes on their side before deprecating the API.
- Regularly remind consumers to implement the changes before the API is deprecated.
Takeaways
API versioning is a powerful way to handle breaking changes and allow your system to evolve. It provides a clean method to introduce new API behaviors while keeping the old ones intact for existing consumers. However, it’s important to use versioning wisely. Only introduce a new version when it’s necessary and beneficial.
Effective communication with your consumers is crucial. Always update your documentation, clearly mark deprecated APIs, and give consumers enough time to transition to new versions.
However, remember that versioning your API does not mean it's always a good idea to make a breaking change and introduce a new version. Ensure there are no other alternatives, or that introducing a new API version is the most worthwhile approach.
Have you implemented API versioning in your system? Was it helpful, or did you encounter any problems during implementation? Make sure to share your experience by commenting below!