But if a breaking change cannot be avoided, then we must abide by semantic versioning (semver) and increase the major version of our API. But where do we store the version data? There are generally two approaches:
- In the URL (for instance, /v2/users): This is by far the easiest to explain and implement, but it's semantically incorrect. This is because URLs should be used to locate a resource; if we add versioning information to the URL, it'd imply that the resource itself is versioned, not the API.
- As part of the Accept header (for instance, Accept: application/vnd.hobnob.api.v2+json): The vnd prefix in the MIME type denotes that this is a vendor-specific MIME type; here, we are using it to specify the API version we want. The +json denotes that the reply could be parsed as JSON. This is the most semantically correct approach, but it also requires more effort to explain to end users.
The URL approach is more practical; the Accept header approach is more semantic. Neither one is "better" than the other. Pick the one that makes sense for you and your audience.
When making a breaking change, apart from increasing the version of your API, make sure you also:
- Provide a grace period whenever possible, that is, a deprecation period where both the legacy and new versions run concurrently, in order to allow developers time to migrate to the newer version
- Provide deprecation warnings in advance, including the date when the older API version will no longer be supported and the date when it will become unavailable altogether
- Provide a clear list of all breaking changes
- Provide clear instructions on how to migrate to the newer version