Use Change Management instead of API Versioning.
Over and over we see HTTP APIs (and now GraphQL APIs) fall into the same versioning trap. Semantic versioning isn’t meant for distributed systems where the goal is to have many components evolving independently. In other words — when was the last time you’ve seen Twitter or Google version number in your browser’s URL?
API providers are trying to fit a square peg into a round hole. They are abusing resource identifiers (or GraphQL type names) to carry information about the version of the particular resource. It’s like having your age in your name. Yes, I’m talking to you John32 and Emmanuel46. And then comes the fallacy of “nested” resources (or nested types): If the resource “John32” (/john32) has nested resource “child” (/john32/child), is the “child” resource of version 32 as well? Or is it a child when John was at version 32? What if the child is changing versions regardless of John32?
The way out is very simple. Here is the easy to follow (and maintain!) API change management strategy. You can use this approach instead of API versioning, and I promise you, if you follow it, you will never have to deal with the nightmares of versioning again. And as a bonus, this strategy works regardless of the protocol or architecture used!
What to version
The first step is to stop using semantic versioning for interfaces in a distributed system. Use semantic versioning for the version of a component’s implementation or the representational formats but NOT for the API between the components.
Here is the breakdown of what to (semantic) version and what not:
- Server has a version
- Client has a version
- Message format passed between server and client has a version
- API description file has a version
- Resource doesn’t have a version
- Relation between resources doesn’t have a version
- API itself doesn’t have a version
Rules for extending
Next, when you are making a change to your API follow these rules for extending:
1. You MUST NOT take anything away
2. You MUST NOT change processing rules
3. You MUST NOT make optional things required
4. Anything you add MUST be optional
If you follow these rules, your changes will always be backward-compatible. It’s clear that because of these rules you want to keep your API surface at the minimum (once you introduce something you can’t take it away). Likewise, the client must be liberal in what it accepts (e.g., ignoring anything it doesn’t understand — Postel’s law).
If a change to:
1.Resource Identifier (URI) including any query parameters and their semantics
2. Resource metadata (e.g. HTTP headers)
3. Resource data (e.g. the HTTP body) fields and their semantics
4. Actions the resource affords (e.g., available HTTP Methods)
5. Relations with other resources (e.g., Links)
Violates one or more of the rules for extending create a new resource variant and leave the existing resource without the change.
If any change to representation format (e.g. HTTP message format) breaks one or more of the rules for the extending, use content-negotiation to provide the new representation format variant and leave existing representation format intact.
If you follow the rules, you will never break anybody who is using your API.
If you’ve created a lot of new resource variants or many new representation formats, it’s clear you will need to phase out some of the old variants. To do so, start marking old variants as deprecated, preferably both in API documentation/description and at the runtime. Make sure to communicate this deprecation to your clients with clear deprecation plan. Eventually, you can remove the deprecated variants from documentation but still keep them available in your API.
As the service provider, it’s your responsibility to make sure all of your clients have migrated to the actual variants before you remove the deprecated versions from your API. And even then, in the case of HTTP, the redirect (303) to an actual variant together with content negotiation is your best friend.
Removing deprecated variants should be done only after a very generous time window for clients, clear communication about the deprecation and even clearer migration path to the new variants. Always use an API analytics over an extended period to monitor the usage (or lack of thereof) of deprecated variants. If any of the variants still have some signs of usage, don’t remove the variant. In this case, you either didn’t try hard enough to convince the clients to migrate to the new variants, the clients didn’t have enough time or incentive (which should be alarming for your API strategy).
Currently optional URI Query parameter first on an existing resource `/greeting?first_name=John&last_name=Appleseed` needs to be made required.
Since this change violates the 3rd rule of extending and could break existing clients a new variant of the resource is created with different URI `/named-greeting?first_name=John&last_name=Appleseed` and the old resource /greeting is left intact, but has been marked as deprecated in the API documentation.