co-cddo / open-standards

Collaboration space for discussing and exploring technical and data standards
134 stars 18 forks source link

API Versioning #17

Closed torgo closed 7 years ago

torgo commented 8 years ago

Discussion on versioning of APIs: best practices, current approaches, relevant standards...

mlewis7127 commented 8 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

philandstuff commented 8 years ago

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).

edent commented 7 years ago

The API documentation standard is being tracked through #31

We have written up some thoughts on versioning at