How to Version a REST API?

REST API versioning helps to iterate faster when the required, breaking or non-breaking, changes are identified. Learn to devise a strategy for API versioning.

To manage this complexity, version your API. Versioning helps us to iterate faster when the needed changes are identified in the APIs.

Change in an API is inevitable as our knowledge and experience of a system improve. Managing the impact of this change can be quite a challenge when it threatens to break existing client integration.

1. When to version?

APIs only need to be up-versioned when a breaking change is made.

Breaking changes include:

  • a change in the format of the response data for one or more calls
  • a change in the request or response type (i.e. changing an integer to a float)
  • removing any part of the API.

Breaking changes should always result in a change to the major version number for an API or content response type.

Non-breaking changes, such as adding new endpoints or new response parameters, do not require a change to the major version number.

However, it can be helpful to track the minor versions of APIs when changes are made to support customers who may be receiving cached versions of data or might be experiencing other API issues.

2. How to version a REST API?

REST doesn’t provide for any specific versioning guidelines, but the more commonly used approaches fall into three categories:

2.1. URI Versioning

Using the URI is the most straightforward approach (and most commonly used as well) though it does violate the principle that a URI should refer to a unique resource. You are also guaranteed to break client integration when a version is updated.

http://api.example.com/v1
http://apiv1.example.com

The version need not be numeric, nor specified using the “v[x]” syntax.

Alternatives include dates, project names, seasons, or other identifiers that are meaningful enough to the team producing the APIs and flexible enough to change as the versions change.

2.2. Versioning using Custom Request Header

A custom header (e.g. Accept-version) allows you to preserve your URIs between versions though it is effectively a duplicate of the content negotiation behavior implemented by the existing Accept header.

Accept-version: v1
Accept-version: v2

2.3. Versioning using “Accept” header

Content negotiation may let you preserve a clean set of URLs, but you still have to deal with the complexity of serving different versions of content somewhere.

This burden tends to be moved up the stack to your API controllers which become responsible for figuring out which version of a resource to send.

The result tends to be a more complex API as clients have to know which headers to specify before requesting a resource.

Accept: application/vnd.example.v1+json
Accept: application/vnd.example+json;version=1.0

In the real world, an API is never going to be completely stable. So it’s important how this change is managed.

A well-documented and gradual deprecation of API can be an acceptable practice for most APIs.

Comments

Subscribe
Notify of
guest
16 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
JiangHongTiao

What about versioning with deprecation?
In general, we do not want to support old versions forever.
The idea I like the most is not to version API.

In the case we need to introduce breaking changes for our API endpoint, our endpoint keep serving always the newest API version (so breaking change for clients).
However to give time for clients to adapt to newer change, we introduce HTTP header:

Accept-Deprecated-Version: <YYYY-MM-DD>

The date specifies when deprecated version will be removed. By this, clients say they still need deprecated version and they acknowledge the date when it will be removed. So they are aware of change and they need to update before that date.
It’s always good to communicate clients changes at our side and give them time to adapt.

Igor Sucupira

From my experience, these are a few reasons that come to mind that may help explain why versioning in the URI became the most common approach:
1. It’s the most explicit.
– If someone integrates with an URI whose path starts with /v2, they can be pretty sure they’ll be getting version 2 until they voluntarily upgrade to a newer version.
– If you manually send a link to someone else, they’ll automatically know which version you’re referring to without needing more information.
2. Even less technical people can easily use their browsers to GET resources that don’t require any non-standard header field or value. This can be very practical even for engineers.

Stefano

Actually Roy Fielding stated that including the version in the URL is really against REST.

Fielding: “By versioning, I meant sticking client-visible interface numbers inside various names so that the client labels every interaction as belonging to a given version of that API.

Unfortunately, versioning interface names only manages change for the API owner’s sake. That is a myopic view of interface design: one where the owner’s desire for control ignores the customer’s need for continuity.”

reference: https://www.infoq.com/articles/roy-fielding-on-versioning/

Doug

He doesn’t state in those sentences that including version in the URL is bad.

He states that including a version number in an *interface* name is bad. Very different.

Ash

If the URL is not an interface in the context of REST, what is?

Josef Bloggs

so, instead of writing /vx/ in url we add “accepted-version=x” in the header and it is all good? How stupid. Consumer needs to know what they are calling, because if in version one you get an apple and in version two you get and orange and you want the apple, you need to know which interface to call.

Adriano

Hi, I like to follow, something like a “default approach” if a version that user desired isn’t informed, I delivery the newest one. For me break the “visible interface” it is always a bad thing.

Jonathan

How do you have a service indicate version in the response? Currently we’re using Content-Type headers. For example, with version 1.3 of a service called “customers”, we’d have something like “Content-Type: application/vnd.com.ourcompany.customers.v1-3+json”. How do you prefer to do it?

Charles

This should apply to the Requests as well not just the Responses.

Jonathan

The article is addressing requests. URIs and Accept headers are for requests.

Shri

Do you deploy various versions as single service Or it should be two separate services running in different pods

Mark

A third option would be to include a version key:value hint in the JSON body.

Dennis

That won’t be of much use with GET.