Closed torgo closed 7 years ago
Versioning is a contentious issue. Roy Fielding gives his best practice for versioning a REST API as:
Don't. Versioning an interface is just a "polite" way to kill deployed applications
Mark Nottingham notes in a blog post that
"versioning is something that should not take place often, because every time you change a version identifier, you're potentially orphaning clients who 'speak' that language".
Versioning an API should be avoided at all costs. Forwards-compatibility must be considered at design time, and all changes should be made backwards-compatible.
The reality is that unlike websites that simply return content to be rendered, there are many APIs that will evolve over time, and potentially take in or return different types of data. This means that we need to be able to version. There are many common approaches to versioning:
1) Version number in the URL hierarchy
GET /v1/vehicles HTTP/1.1
This is the most common approach to API versioning in the industry. This is simple to code and easy for developers to understand. It also means that APIs can be bookmarked and tested in a browser. Examples of APIs that use version numbers in the URI include:
API | Example |
---|---|
Twitter Search API | https://api.twitter.com/1.1/search/ |
Google Search API | https://www.googleapis.com/customsearch/v1 |
Google GMail API | https://www.googleapis.com/gmail/v1/ |
Stripe API | https://api.stripe.com/v1/charges |
PayPal API | https://api.paypal.com/v1/payments/ |
Facebook Graph API | https://graph.facebook.com/v2.5/ |
Salesforce REST API | https://na1.salesforce.com/services/data/v35.0/ |
GOV.UK Pay | https://publicapi-integration-1.pymnt.uk/v1/payments |
This approach requires a new URL whenever there is a breaking change. Semantically that implies a different resource, which is likely not to be correct. It also breaks the view from the W3C that Cool URIs don't change
What makes a cool URI? A cool URI is one which does not change. What sorts of URI change? URIs don't change: people change them.
2) Version number in a custom header
GET /vehicles HTTP/1.1
X-API-Version: 1
Mark Nottingham describes this approach in a blog post as:
broken and wrong for a whole of mess of reasons
He goes on to explain that:
HTTP gives you a number of ways to introduce both compatible and incompatible changes, primarily using new resources and media types. While adding a version header to this mix might seem to leave your options open, it's actually a bad API smell that indicates a tendency to treat HTTP more like RPC, a la SOAP
This approach does not have the simplicity of URL versioning, and also ignores how HTTP should handle content negotiation.
3) Version number in the media type
Content-type: application/vnd.dvla.vehicle.v1+json
The approach of using custom media types and content negotiation means the URI remains the same, and the consumer can choose the format of the data to be received. This is the approach adopted by the GitHub API
In the case of the GitHub API, the consumer can specify a version of the API in the Accept header when making a request
Accept: application/vnd.github.v3+json
It is also possible to use this approach to version resources individually, rather than at the API level. This can provide benefits in that only clients of resources that have introduced a breaking change will need to upgrade. However, it also adds more complexity, and clients need to specify different media types for each resource. This approach of adding lots more media types has its detractors as voiced by Mark Nottingham in his blog
I don't think we need lots more media types. The media types that should be used on the wire are things like application/xml and application/json, not application/vnd.me.heres-a-stab-in-the-dark-get-used-to-my-weird-conventions.
4) Hypertext as the Engine of Application State (HATEOS) HATEOS is the pinnacle of the Richardson REST Maturity Model. Roy Fielding has stated that REST is designed primarily to improve evolvability. This is the ability to change over time, in response to user needs or a changing environment, without starting over. REST is designed to steer developers towards handling change by observing and adapting to changes in content instead of interfaces.
HATEOS works by providing a standard entry point, that returns a series of links with all the available actions that can take place. The only links that would be returned would be those that are valid to be carried out. This does mean sending more data that necessary on an initial response.
One of the major issues of HATEOS is that:
JSON has no built-in support for hyperlinks, which are a fundamental building block on the Web
There are a number of competing media types available that provide a way of representing links by defining their own keywords to be used. For example:
HATEOS has started to be implemented in a number of APIs such as those provided by GitHub and Paypal.
I am starting to see more and more use of versioning either in the media type or in a profile attached to the media type. However, these media types never seem to be registered with IANA
JSON has no built-in support for hyperlinks, which are a fundamental building block on the Web
This is true, and even more true for formats such as CSV or TSV. One possible way to get hypermedia from media-types that don't support linking natively is to use RFC 5988 Link headers (another mnot thing).
The API documentation standard is being tracked through #31
We have written up some thoughts on versioning at
Discussion on versioning of APIs: best practices, current approaches, relevant standards...