{"id":241,"date":"2012-03-12T17:17:56","date_gmt":"2012-03-12T17:17:56","guid":{"rendered":"http:\/\/www.lexicalscope.com\/blog\/?p=241"},"modified":"2014-09-15T08:48:07","modified_gmt":"2014-09-15T08:48:07","slug":"how-are-rest-apis-versioned","status":"publish","type":"post","link":"https:\/\/www.lexicalscope.com\/blog\/2012\/03\/12\/how-are-rest-apis-versioned\/","title":{"rendered":"How are REST APIs versioned?"},"content":{"rendered":"<p>I am currently working on a REST API, and the question was raised, how are, and how should, REST APIs be versioned? Here are the results of my research.<\/p>\n<p>It seems that there are a number of people recommending using Content-Negotiation (the HTTP &#8220;Accept:&#8221; header) for API versioning. However, <em>none<\/em> of the big public REST APIs I have looked at seem to be using this approach. They almost exclusively put the API version number in the URI, with the odd exception using a custom HTTP header. I am at somewhat of a loss to explain this disconnect.<\/p>\n<h2>Versioning strategies in discussions<\/h2>\n<table>\n<tbody>\n<tr>\n<th>Post<\/th>\n<th>Versioning<\/th>\n<\/tr>\n<tr>\n<td><a title=\"stack overflow API versioning\" href=\"http:\/\/stackoverflow.com\/a\/398564\/72810\">Stack Overflow 1<\/a><\/td>\n<td>URI<\/td>\n<\/tr>\n<tr>\n<td><a title=\"stack overflow API versioning\" href=\"http:\/\/stackoverflow.com\/a\/6750376\/72810\">Stack Overflow 2<\/a><\/td>\n<td>Content Negotiation<\/td>\n<\/tr>\n<tr>\n<td><a title=\"versioning rest API\" href=\"http:\/\/thereisnorightway.blogspot.com\/2011\/02\/versioning-and-types-in-resthttp-api.html\">blog post by Jeremy<\/a><\/td>\n<td>Content Negotiation<\/td>\n<\/tr>\n<tr>\n<td><a title=\"YCombinator REST API versioning\" href=\"http:\/\/news.ycombinator.com\/item?id=1523664\">ycombinator discussion<\/a><\/td>\n<td>some opinions both ways<\/td>\n<\/tr>\n<tr>\n<td><a title=\"stack overflow API versioning\" href=\"http:\/\/stackoverflow.com\/a\/975394\/72810\">Stack Overflow 3<\/a><\/td>\n<td>Content Negotiation<\/td>\n<\/tr>\n<tr>\n<td><a title=\"stack overflow API versioning\" href=\"http:\/\/stackoverflow.com\/a\/1250488\/72810\">Stack Overflow 4<\/a><\/td>\n<td>Content Negotiation<\/td>\n<\/tr>\n<tr>\n<td><a title=\"notmessenger blog post on rest API versioning\" href=\"http:\/\/www.notmessenger.com\/rest\/3-tenets-for-implementing-a-rest-api\/\">notmessenger blog post<\/a><\/td>\n<td>URI (against all headers)<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Peter Williams rest versioning\" href=\"http:\/\/barelyenough.org\/blog\/2008\/05\/versioning-rest-web-services\/\">Peter Williams<\/a><\/td>\n<td>Content Negotiation (strongly against URIs)<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"Apigee API versioning\" href=\"http:\/\/blog.apigee.com\/detail\/api_restful_design_question_verisioning_number_in_the_url\/\">Apigee Blog post on API versioning<\/a><\/td>\n<td>URI (some discussion)<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Mark Nottingham on API versioning\" href=\"http:\/\/www.mnot.net\/blog\/2011\/10\/25\/web_api_versioning_smackdown\">Mark Nottingham REST versioning<\/a><\/td>\n<td>Recommending essentially versionless extensibility with a HATEOS approach<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Nick Berardi Rest Versioning\" href=\"http:\/\/coderjournal.com\/2010\/09\/simple-rest-api-versioning-using-mef-and-mvc\/\">Nick Berardi on REST versioning<\/a><\/td>\n<td>URI<\/td>\n<\/tr>\n<tr>\n<td><a title=\"RESTify API versioning\" href=\"http:\/\/mcavage.github.com\/node-restify\/\">Restify<\/a><\/td>\n<td>&#8220;Accept-Version&#8221; header<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Tom Maguire rest versioning\" href=\"http:\/\/tomdmaguire.wordpress.com\/2011\/11\/12\/creating-a-restful-versioned-api-using-sinatra\/\">Tom Maguire on REST versioning<\/a><\/td>\n<td>Content Negotiation<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Nicholas Zakas on Rest Versioning\" href=\"http:\/\/www.nczonline.net\/blog\/2011\/02\/22\/the-importance-of-being-versioned\/\">Nicholas Zakas on Rest Versioning<\/a><\/td>\n<td>URI<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Steve Klabnik on REST Versioning\" href=\"http:\/\/blog.steveklabnik.com\/posts\/2011-07-03-nobody-understands-rest-or-http\">Steve Klabnik on Rest Versioning<\/a><\/td>\n<td>Content Negotiation + HATEOS<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Luis Rei on REST versioning\" href=\"http:\/\/publish.luisrei.com\/rest.html\">Luis Rei on Rest Versioning<\/a><\/td>\n<td>Content Negotiation with (;version=1.0)<\/td>\n<\/tr>\n<tr>\n<td><a title=\"kohana forum on REST versioning\" href=\"http:\/\/forum.kohanaframework.org\/discussion\/8498\/restful-api-kohana\/p1\">kohana forum discussion on REST versioning<\/a><\/td>\n<td>Many Opinions<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Troy Hunt on REST versioning\" href=\"http:\/\/www.troyhunt.com\/2014\/02\/your-api-versioning-is-wrong-which-is.html\">Troy Hunt on REST versioning<\/a><\/td>\n<td><a title=\"alternative location\" href=\"http:\/\/java.dzone.com\/articles\/your-api-versioning-wrong\">Accept Header but also support custom header and URL<\/a><\/td>\n<\/tr>\n<tr>\n<td><a title=\"Paul Gear on API versioning\" href=\"http:\/\/blog.librenms.org\/2014\/09\/restful-apis\/\">Paul Gear REST versioning<\/a><\/td>\n<td>Recommending essentially versionless extensibility with a HATEOS approach<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Versioning strategies in popular REST APIs<\/h2>\n<table>\n<tbody>\n<tr>\n<th>API Name<\/th>\n<th>Versioning<\/th>\n<th>Example<\/th>\n<\/tr>\n<tr>\n<td><a title=\"Twillo API\" href=\"http:\/\/www.twilio.com\/docs\/api\/rest\/making-calls\">Twillo<\/a><\/td>\n<td>date in URI<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"twitter api versioning\" href=\"https:\/\/groups.google.com\/forum\/?fromgroups#!topic\/twitter-api-announce\/K3C9bqSuwXU\">Twitter<\/a><\/td>\n<td>URI<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"Atlassian API versioning\" href=\"https:\/\/developer.atlassian.com\/display\/REST\/Atlassian+REST+API+Design+Guidelines+version+1\">Atlassian<\/a><\/td>\n<td>URI<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"google search api\" href=\"http:\/\/code.google.com\/apis\/customsearch\/v1\/using_rest.html\">Google Search<\/a><\/td>\n<td>URI<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"github api versioning\" href=\"http:\/\/develop.github.com\/p\/general.html\">Github API<\/a><\/td>\n<td>URI\/Media Type in v3<\/td>\n<td><a title=\"github versioning future\" href=\"http:\/\/developer.github.com\/v3\/media\/#api-v3-media-type-and-the-future\">Intention is to remove versioning in favour of hypermedia<\/a> &#8211; current application\/vnd.github.v3<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Azure\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windowsazure\/dd894041.aspx\">Azure<\/a><\/td>\n<td>Custom Header<\/td>\n<td>x-ms-version: 2011-08-18<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/developers.facebook.com\/docs\/apps\/versions\" title=\"facebook versioning policy\">Facebook<\/a><\/td>\n<td>URI\/optional versioning<\/td>\n<td>graph.facebook.com\/v1.0\/me<\/td>\n<\/tr>\n<tr>\n<td><a title=\"bing maps api versioning\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff701714.aspx\">Bing Maps<\/a><\/td>\n<td>URI<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"google maps\" href=\"http:\/\/code.google.com\/apis\/maps\/documentation\/staticmaps\/upgrade.html\">Google maps<\/a><\/td>\n<td>unknown\/strange<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"netflix api versioning\" href=\"http:\/\/developer.netflix.com\/docs\/REST_API_Conventions#0_pgfId-1009147\">Netflix<\/a><\/td>\n<td>URI parameter<\/td>\n<td>http:\/\/api.netflix.com\/catalog\/titles\/series\/70023522?v=1.5<\/td>\n<\/tr>\n<tr>\n<td><a title=\"salesforce api versioning\" href=\"http:\/\/www.salesforce.com\/us\/developer\/docs\/api\/index.htm\">Salesforce<\/a><\/td>\n<td>URI with version introspection<\/td>\n<td>{<br \/>\n&#8220;label&#8221;:&#8221;Winter &#8217;10&#8221;<br \/>\n&#8220;version&#8221;:&#8221;20.0&#8243;,<br \/>\n&#8220;url&#8221;:&#8221;\/services\/data\/v20.0&#8243;,<br \/>\n}<\/td>\n<\/tr>\n<tr>\n<td><a title=\"google data api versioning\" href=\"http:\/\/code.google.com\/apis\/gdata\/docs\/developers-guide.html\">Google data API (youtube\/spreadsheets\/others)<\/a><\/td>\n<td>URI parameter or custom header<\/td>\n<td>&#8220;GData-Version: X.0&#8221; or &#8220;v=X.0&#8221;<\/td>\n<\/tr>\n<tr>\n<td>Flickr<\/td>\n<td>No versioning?<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"Digg API versioning\" href=\"http:\/\/apidoc.digg.com\/w\/page\/17759000\/FrontPage\">Digg<\/a><\/td>\n<td>URI<\/td>\n<td>http:\/\/services.digg.com\/2.0\/comment.bury<\/td>\n<\/tr>\n<tr>\n<td><a title=\"delicious API versioning\" href=\"http:\/\/delicious.com\/developers\">Delicious<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/api.del.icio.us\/v1\/posts\/update<\/td>\n<\/tr>\n<tr>\n<td><a title=\"lastFM api versioning\" href=\"http:\/\/www.last.fm\/api\/intro\">Last FM<\/a><\/td>\n<td>URI<\/td>\n<td>http:\/\/ws.audioscrobbler.com\/2.0\/<\/td>\n<\/tr>\n<tr>\n<td>LinkedIn<\/td>\n<td>URI<\/td>\n<td>http:\/\/api.linkedin.com\/v1\/people\/~\/connections<\/td>\n<\/tr>\n<tr>\n<td><a title=\"foursquare API versioning\" href=\"https:\/\/developer.foursquare.com\/docs\/\">Foursquare<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/api.foursquare.com\/v2\/venues\/40a55d80f964a52020f31ee3?oauth_token=XXX&amp;v=YYYYMMDD<\/td>\n<\/tr>\n<tr>\n<td><a title=\"freebase api versioning\" href=\"http:\/\/wiki.freebase.com\/wiki\/ApiSearch\">Freebase<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/www.googleapis.com\/freebase\/v1\/search?query=nirvana&amp;indent=true<\/td>\n<\/tr>\n<tr>\n<td><a title=\"paypal versioning\" href=\"https:\/\/cms.paypal.com\/us\/cgi-bin\/?cmd=_render-content&amp;content_ID=developer\/e_howto_api_nvp_NVPAPIOverview\">paypal<\/a><\/td>\n<td>parameter<\/td>\n<td>&amp;VERSION=XX.0<\/td>\n<\/tr>\n<tr>\n<td><a title=\"twitpic\" href=\"http:\/\/dev.twitpic.com\/docs\/2\">Twitpic<\/a><\/td>\n<td>URI<\/td>\n<td>http:\/\/api.twitpic.com\/2\/upload.format<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Etsy API versioning\" href=\"http:\/\/www.etsy.com\/developers\/documentation\/getting_started\/api_basics\">Etsy<\/a><\/td>\n<td>URI<\/td>\n<td>http:\/\/openapi.etsy.com\/v2<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Tropo API versioning\" href=\"https:\/\/www.tropo.com\/docs\/rest\/starting_session.htm\">Tropo<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/api.tropo.com\/1.0\/sessions<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Tumblr\" href=\"http:\/\/www.tumblr.com\/docs\/en\/api\/v2\">Tumblr<\/a><\/td>\n<td>URI<\/td>\n<td>api.tumblr.com\/v2\/user\/<\/td>\n<\/tr>\n<tr>\n<td><a title=\"openstreetmap API versioning\" href=\"http:\/\/wiki.openstreetmap.org\/wiki\/API_v0.6\">openstreetmap<\/a><\/td>\n<td>URI and response body<\/td>\n<td>http:\/\/server\/api\/0.6\/changeset\/create<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Ebay API versioning\" href=\"http:\/\/developer.ebay.com\/Devzone\/shopping\/docs\/Concepts\/ShoppingAPIGuide.html\">Ebay<\/a><\/td>\n<td>URI (I think)<\/td>\n<td>http:\/\/open.api.ebay.com\/shopping?version=713<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Reddit API versioning\" href=\"https:\/\/github.com\/reddit\/reddit\/wiki\/API\">Reddit<\/a><\/td>\n<td>No versioning?<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"Groupon API versioning\" href=\"http:\/\/sites.google.com\/site\/grouponapiv2\/api-resources\/channels\/deals\">Groupon<\/a><\/td>\n<td>URI<\/td>\n<td>http:\/\/api.groupon.com\/v2\/channels\/\/deals{.json|.xml}<\/td>\n<\/tr>\n<tr>\n<td><a title=\"geonames API versioning\" href=\"http:\/\/www.geonames.org\/export\/\">Geonames<\/a><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"wikipedia\" href=\"http:\/\/www.mediawiki.org\/wiki\/API\">Wikipedia<\/a><\/td>\n<td>no versioning I think?<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><a title=\"bitly API versioning\" href=\"http:\/\/code.google.com\/p\/bitly-api\/wiki\/ApiDocumentation\">Bitly<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/api-ssl.bitly.com\/v3\/shorten<\/td>\n<\/tr>\n<tr>\n<td><a title=\"disqus API versioning\" href=\"http:\/\/disqus.com\/api\/docs\/posts\/remove\/\">Disqus<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/disqus.com\/api\/3.0\/posts\/remove.json<\/td>\n<\/tr>\n<tr>\n<td><a title=\"yammer API versioning\" href=\"https:\/\/developer.yammer.com\/api\/#introduction\">Yammer<\/a><\/td>\n<td>URI<\/td>\n<td>\/api\/v1<\/td>\n<\/tr>\n<tr>\n<td><a title=\"dropbox API versioning\" href=\"https:\/\/api.dropbox.com\/1\/oauth\/request_token\">Drop Box<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/api.dropbox.com\/1\/oauth\/request_token<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Amazon Simple Queue Service API versioning\" href=\"http:\/\/docs.amazonwebservices.com\/AWSSimpleQueueService\/latest\/APIReference\/Welcome.html?r=7475\">Amazon Simple Queue Service (Soap)<\/a><\/td>\n<td>URI Parameter and WSDL URI<\/td>\n<td>&amp;Version=2011-10-01<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Youtube data API versioning\" href=\"https:\/\/developers.google.com\/youtube\/v3\/docs\/\">Youtube data API versioning<\/a><\/td>\n<td>URI<\/td>\n<td>https:\/\/www.googleapis.com\/youtube\/v3<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Versioning strategies in popular REST Libraries<\/h2>\n<table>\n<tbody>\n<tr>\n<th>Library Name<\/th>\n<th>Versioning<\/th>\n<th>Example<\/th>\n<\/tr>\n<tr>\n<td><a title=\"node-restify\" href=\"http:\/\/mcavage.me\/node-restify\/#Routing\">node-restify<\/a><\/td>\n<td><a href=\"http:\/\/semver.org\/\" title=\"semantic versioning\">semver<\/a> versioning in an accept-Version header<\/td>\n<td>accept-version: ~3<\/td>\n<\/tr>\n<tr>\n<td><a title=\"Jersey\" href=\"http:\/\/maxenglander.com\/2013\/04\/23\/basic-restful-api-versioning-in-jersey.html\">Jersey<\/a><\/td>\n<td>description of how to do Accept: header versioning in Jersey<\/td>\n<td>Accept: application\/vnd.musicstore-v1+json<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>I am currently working on a REST API, and the question was raised, how are, and how should, REST APIs be versioned? Here are the results of my research. It seems that there are a number of people recommending using &hellip; <a href=\"https:\/\/www.lexicalscope.com\/blog\/2012\/03\/12\/how-are-rest-apis-versioned\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-241","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p2e3P7-3T","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/posts\/241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/comments?post=241"}],"version-history":[{"count":10,"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/posts\/241\/revisions"}],"predecessor-version":[{"id":5921,"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/posts\/241\/revisions\/5921"}],"wp:attachment":[{"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/media?parent=241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/categories?post=241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lexicalscope.com\/blog\/wp-json\/wp\/v2\/tags?post=241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}