Versioning Your API
Choosing an API versioning strategy can be difficult. There are many approaches and
each come with their own pros and cons. Two of the most common practices are to version
in the URL or with headers. For Heroku’s public API we decided to version with the
Accept
header.
URL Versioning is Dead Simple
If you’re not familiar with URL versioning it’s simply having the version number as
part of the URI, for instance, example.com/v2/resources
. This approach is very clear
and easy to call in code or at the command-line. The problem I see with URL versioning
is that it’s not forgiving. If/when the version is no longer available the server will
return a 404
response.
Accept Header Versioning is Forgiving
To version with the Accept
header the API has to listen for a custom media type and
respond accordingly. Github chose the media type application/vnd.github.v3+json
where 3
is the API version. For Heroku’s API we decided on
application/vnd.heroku+json; version=3
, also where 3
is our version of the API.
In section 14.1 of the HTTP Spec the document indicates that multiple media types
can be passed in the Accept
header. If the first media type requested isn’t available
the next type can be returned and it continues down the line. If the following Accept
header is sent to an endpoint that does not have a version 3 response it will disregard
the Heroku media type and return the default response as JSON.
Accept: application/vnd.heroku+json; version=3, application/json
I prefer this approach over URL versioning because of the ability to set multiple types in one request.
Understanding a Custom Media Type
A media type consists of two or more parts—type, subtype, and optional parameters.
The Media Type Spec states the application
type is meant for content that is
to be processed by applications before being viewed or usable by a user. That
sounds perfect for an API.
Sub types that begin with vnd
are vendor specific media types. These media types
are defined and controlled by the vendor. Creation of and modifications to vendor
media types aren’t subject to community reviews.
The +json
indicates that the content is a JSON structure. This is key to custom
media types, whether a vendor type or experimental (prefixed with x-
), because
it shows how the data should be parsed once received.
Lastly, parameters allow for additional information to be passed without changing the
media type. A version
parameter can be used to support multiple API versions during
a transition period.
In the case of Heroku’s API we will respond to application/json
by default and
application/vnd.heroku+json; version=2
and application/vnd.heroku+json; version=3
upon request. The default response will render the same as vnd.heroku+json; version=2
until version 3 is completed and widely adopted. At that point the default
application/json
response will render the same as vnd.heroku+json; version=3
and
version 2 will be available through the custom media type.