DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Trending

  • SRE vs. DevOps
  • Reactive Programming
  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Automating the Migration From JS to TS for the ZK Framework

Trending

  • SRE vs. DevOps
  • Reactive Programming
  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Automating the Migration From JS to TS for the ZK Framework
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Best Practice: API Versioning for HTTP REST Interfaces

Best Practice: API Versioning for HTTP REST Interfaces

Being able to handle (and negotiate!) different major versions in parallel is not always easy — but sometimes, it's quite helpful.

Meike Chabowski user avatar by
Meike Chabowski
·
Feb. 08, 17 · Opinion
Like (8)
Save
Tweet
Share
40.13K Views

Join the DZone community and get the full member experience.

Join For Free

We are providing more and more APIs with the wonderful HTTP REST approach. APIs evolve over time, often unexpectedly — so it makes sense to get into some API versioning best practices right from day zero. We were asked to join Crowbar guys’ discussion to share our experience with versioning APIs. This article is an attempt to formalize our solution and prepare it for a wider audience.

So, imagine you have different API consumers out of your area of control. Some of them definitely will lag behind the latest release. As a back-end server developer, you need to find a way to serve them all with the appropriate API versions.

You’ll have to invent some smart custom solution so that you know which API to serve which client, right?

Use HTTP Content-Type Negotiation to Expose Versioning

Actually, no. HTTP already has all you need — just use it! The technique is called content-type negotiation and has existed as IETF RFC for a very long time.

But how does one use text/html and application/json to serve the cause?

Use Versioned VND Content Types

Well, there’s an HTTP RFC 6838 for custom vendor-specific MIME types. It reserves a whole “vendor tree” with free-form entries looking like type/vnd.producer’s name followed by media type name [+suffix].

Crowbar’s protocol uses application/json as an underlying data format, so the resulting MIME type will be application/vnd.crowbar+json. Or, when we add a version number to that type — it was the original intention, wasn’t it? — application/vnd.crowbar.v2+json.

Who and When to Register a VND MIME Type

RFC states that “anyone who needs to interchange files associated with some product” can register such a new vnd entry. The usage of unregistered vnd types is not frowned upon in the community, so no need to hurry with your registration, either. Settle the API, make sure that it works, release it to the public, and only then fill in the form.

So, we ask for application/vnd.crowbar.v2+json from the second generation of Crowbar clients and that’s it, correct?

Use major.minor Versioning Scheme

From our experience with SCC-related tools, APIs grow frequently and experience breaking changes infrequently. So, we want to add some backwards-compatibility indication to our API versions, as semantic versioning did with software release versions.

Our custom MIME types now look like application/vnd.crowbar.v2.3+json and expose a couple of important properties:

Minor Versions Are Backwards-Compatible

Thus, you should update them on every change.A single server handler (running the latest version) can handle all previous minor versions. Your 1.7 server provides every endpoint that your 1.3 client ever wants to see. The client’s requests provide enough data and context for server’s handlers, and the server’s responses can have some extra JSON fields. Ignore those. Everything is backwards-compatible. YAY!

Major Version Changes Indicate Breaking Changes

Every major change requires a separate server handler. Your endpoint now requires some additional data from the client — increase the major version. You’ve removed some URLs from API — increase the major version. You’ve finally implemented HTTP status codes for errors instead of response headers — you know what to do. (Why didn’t you do that from the beginning, by the way?!)

Sometimes, it might even be a good idea to branch your code base for a new major API version. Then, you can run two separate server instances with two different API versions. You can route client requests to the right back-end server basing on the Accept header contents. There’s a basic example of such routing for Nginx at the bottom of this article.

Content Type Negotiation Can Help With Older Servers

Imagine you have some not very up-to-date server, which supports API versions 1.3 and 2.1.

1.3 is in “maintenance mode” and hasn’t been updated for a long time.

2.x branch evolves rapidly, so your shiny brand-new client requires at least 2.4 to get data right.

With properly implemented content type negotiation on both sides, your client will send Accept: application/vnd.foobar.v2.4+json, application/vnd.foobar.v1.3+json; q=0.1 to the server. The server will be able to serve only the less prioritized API, so the answer will be with Content-Type: application/vnd.crowbar.v1.3+json. And that’s it! Your API versioning scheme just provided you some (weak) forward-compatibility guarantees in addition to (strong) backward-compatibility ones.

Respond With the Latest Version to “X Version” Requests

Sometimes, your clients don’t care about API versions. Maybe they are writing curl commands in their command-line interface. Maybe they’re toying with API in some fancy GUI. Maybe it’s some unimportant code, and breaking the integration won’t cause any tears.

This is not a problem. Simply route to the most recent version of API, process the request, and state your current API version in the ContentType header.

The main trick here is to specify your version, even in the case of request failures. Then, your client can spot the version change in the reply of the API call which “…was working OK just before now. Well, maybe a week ago. Or two…” Also, this will make API version probing trivial; just GET any URL and look at the content-type in the response.

Recap

  • Be a good webizen; use HTTP built-in content type negotiations for your API versioning.
  • Create a custom MIME type from VND tree.
  • Bump versions in your server-side code on every tiniest change.
  • Indicate version in your responses, especially in error cases.
  • Being able to handle (and negotiate!) different major versions in parallel is not always easy, but sometimes quite helpful.

Bonus: Nginx Configuration for VND-Dependent Routing

You might want to keep your incompatible major versions in different application instances. Then, you can route your incoming requests to the right backend (with Nginx):

Image title

API REST Web Protocols

Published at DZone with permission of Meike Chabowski, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • SRE vs. DevOps
  • Reactive Programming
  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Automating the Migration From JS to TS for the ZK Framework

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: