Versioning
Each time you modify the web API or change the schema of resources, you add a version number to the URI for each resource. The previously existing URIs should continue to operate normally by returning resources that conform to their original schema.
https://api.contoso.com/v2/customers/3
This versioning mechanism is simple but depends on the server to route the request to the appropriate endpoint. However, it can become unwieldy as the web API matures through several iterations and the server has to support many different versions. From a purist’s point of view, in all cases, the client applications fetch the same data (customer 3), so the URI shouldn’t differ according to the version. This schema also complicates the implementation of HATEOAS because all links need to include the version number in their URIs.
Other versioning methods
Query string versioning, Header versioning
When should API versioning be done
You should version your API whenever you make a change that will require consumers to modify their codebase in order to continue using the API. This type of change is known as a “breaking change,” and it can be made to an API’s input and output data structures, success and error feedback, and security mechanisms.
Example of breaking changes
Renaming a property or endpoint: You might sometimes want to rename a property or method so that its meaning is clearer. While clear naming is important from an API design standpoint, it’s almost impossible to change property or method names once the API is in production without breaking your consumers’ code.
Turning an optional parameter into a required parameter:
Modifying a data format or type - You may sometimes realize that several properties, such as firstName and lastName, should instead exist within a user object, instead of as separate properties that take string values. While this type of change would improve your API’s design, it is nevertheless a breaking change that will cause a parsing exception.
Modifying a property’s characteristics: You may occasionally be tempted to change the rules for certain properties. For instance, a description property of type: string may have a maxLength rule that you discover is too low or too high. This type of change will have different results depending on its implementation, including database and UI errors.
Scheme
Semantic versioning follows a three-part number format (i.e., 3.2.1), in which the first number represents a major update that might include breaking changes, the second number represents an update that includes new, backward-compatible features, and the third number represents bug fixes or patches.
Best Practices for API Versioning
Design with extensibility in mind: It’s important to think strategically about versioning during the API design process. For instance, certain data types, such as booleans and arrays of atomics, are more vulnerable to breaking changes than others, so it’s best to omit them from your API design when possible.
Decouple implementation versioning and contract versioning: When it comes to versioning, it’s important to consider the API’s implementation separately from its contract. For instance, if you rewrite a Node.js implementation in Rust, but the contract doesn’t change, you should not release a new version of the API.
Know your consumers: It’s important to understand how your consumers are using your API when you’re deciding whether to make changes. This involves being aware of the invisible API contract, which refers to unexpected implementations of your API. For example, consumers may access a property in an object by its index, rather than its property name. While this implementation was not intended by the API’s producers, it should nevertheless be accounted for during the versioning process.