Versioning web services

Freshness Warning
This article is over 11 years old. It's possible that the information you read below isn't current.

When I add a new feature to Tagyu’s web service API, how should I best version it? I don’t want to maintain and support multiple, old copies of the API, but I also need to ensure I don’t break backward compatibility. A change to the API can’t cause existing apps out there to stop working.

At first I thought this was an easy problem. I’d simply ensure that any time I made a change to the API the changes would be additive. I wouldn’t remove any data, I wouldn’t change the location of representation of the data, I’d only add new data. If a case came up where I needed to change how the XML data is stored, then I’d consider maintaining parallel versions of the API for a period of time. I’d figure out how to do that when the time came. Amazon Web Services inserts their API version into the URL, but that’s always seemed a bit clunky to me.

Today’s new API feature made me rethink how I change the API and represent different versions. It made me rethink what changes should be even considered as a new version. Today’s change involved the insertion of a couple of attributes to one of the XML tags. Shouldn’t be a problem right? That’s what I thought, too.

Before the change, the XML node for a suggested tag looked like this:

<tag>sometag</tag>

After the change, it looked like this:

<tag rel="related" href="http://tagyu.com/api/tag/sometag">
	sometag
</tag>

Those two new attributes broke some APi implementations, including my own software, the Tagyu Movable Type plugin. The plugin uses XML::Simple to parse the API’s response. And as far as XML::Simple is concerned, those two formats are completely different XML structures. XML simple represents the first one as this…

{
    'tag' => 'sometag'
}

And the second as this …

{
	'tag' => {
	 	'rel' => 'related',
		'href' => 'http://tagyu.com/api/tag/sometag'
		'content' => 'sometag'
	 }
}

The Tagyu plugin accesses the tag through $tags->{'tag'} but under the new structure, that’s not the tag at all, it’s a hash that contains the tag, among other things.

The point of all this is that even though I thought I was being careful, today’s API change broke things. And that’s bad. It should never happen.

I’m looking for thoughts on how to version a web services API or really any software that’s delivered as a service. How do you prevent changes from having adverse effects while at the same time providing improvements. Is different API versions at different URLs really best or only way to go?

Michael Buckbee
February 14, 2006 2:57 PM

Trying to find the the "best" solution is always a tough one, but I think the simplest (by which I mean the one most guaranteed to not break some downstream application) is the one you suggested: versioned URL's. Any other method I can think of (additional input variables, an application registry so you "know" when somebody signed up and are dynamically feeding them the right one, etc) strikes me as very non-discoverable and fragile.

Byrne Reese
February 14, 2006 3:10 PM

Here are the methods I am familar with to version APIs: * Place version number as an argument/parameter (this is done in LiveJournal's XMLRPC API) and a few others that I am aware of. The parameter must be optional and must default to the most recent version. (SOAP does this, and Grand Central did this) * Place version number in the declared namespace for the XML document/response. The namespace would only need to be changed for any non-backwards compatible change (e.g. renaming an element) * Place version number in the URL and create separate endpoints (Amazon does this as you point out) I myself tend to favor Amazon's approach because I personally find it easier to maintain. If you rev your protocol a lot (which if one is doing, should realize is a problem) trying to handle all the various interface versions in a single code base is cumbersome at best. Plus when it comes time to discontinue a deprecated API then you just expire the URL. What is easier then that. But vendors should architect their APIs, just as the architect their web UIs: clearly abstract form and function. If they do that properly then it really doesn't matter what technique you use provided that it is very well documented. That and they should put a lot of thought into their API prior to releasing it, and avoid changing the interface too frequently.

Colin D. Devroe
February 14, 2006 4:51 PM

I agree with Byrne: the choice is yours. One way I've done it, is to actually have the url represent large version upgrades. I've only had to put together a few APIs and it was not used on a grand scale (such as Amazons), but this worked out fairly well. Small revisions, meaning those that would not effect any of those using the API, were done by simply showing the version within the XML. This way those using it could chose to not use a specific build if they so chose. However, for larger version upgrades I would literally allow those that chose to change the calling URL. api1.domain.com (example, not really what I ended up using), api2 and so on. The rest was handled by .htaccess mod_rewrite rules which would end up simply changing another URL arg like version=1, or whatever. This way, those using the API did not have to change any of their argument calls (which if their application is sloppy could be hundreds of changed lines), but only their major call. I hope that made any sense at all, I haven't eaten yet today.

Adam Kalsey
February 14, 2006 6:39 PM

The thing is, I thought I _had_ thought out the API. I'd made plans for hwo to grow it slowly without making wholesale changes to it. What I failed to account for was some of the idiosyncracies of parsers. XML::Simple by default transposed the XML into an odd structure. So it's now obvious to me that even simple changes aren't so simple. I don't really like including version numbers in the URL for a number of reasons. First off, it exposes internal administrivia. The developer shouldn't have to care what version of the API they're using. Secondly, it doesn't seem like a very RESTful thing to do. What's more RESTful? example.com/product/1234 or example.com/v1/product/1234

Colin D. Devroe
February 16, 2006 6:30 AM

Adam: I agree totally. However, if you have a user-base, and an upgrade to an API will "break" whatever your current base has developed, somehow making the distinction between versions is absolutely vital.

Vincent D Murphy
February 18, 2006 8:14 AM

One thing which I think would help, if only on a 'social' level, is to offer a feed of all API changes. That way users know to re-run their tests, and hopefully even catch up. The XML::Simple behaviour is interesting; a good use case, and an example motivating the use of versioning. I would prefer a module which complicates the simple case in order to have an attribute be just an extra hash entry. By always having a 'content' hash entry, at the cost of an extra dereference in the simple case, for example. Less Magic. From a REST perspective, the changes in your example are to the representation format, not the application protocol, and the software using the representations (XML::Simple) seems a bit too brittle to cope with such a simple, additive change. (I know much of what I'm saying assumes an ideal world, but I am coming at this from an architectural level of abstraction :) )

Chris Lihosit
March 16, 2006 11:20 AM

This discussion makes me wonder: If the whole notion of using the REST design pattern lay with 1 URI == 1 Resource, then doesn't changing the URI to reflect a difference in XML reduce the effectiveness of the whole pattern in that duplication of information (with little benefit) is inevitable? I'd categorize the XML::Simple behavior as a bug, since in either case of the example XML node above "sometag" is most certainly content to the element. On your later post, really like the concept of a versioning system, that returns latest, past and future nodes, but really isn't that exchanging the practice of [some URI]/v1/[more URI] with just a more verbose "v1" ? Love to hear your thoughts.

Your comments:

Text only, no HTML. URLs will automatically be converted to links. Your email address is required, but it will not be displayed on the site.

Name:

Not your company or your SEO link. Comments without a real name will be deleted as spam.

Email: (not displayed)

If you don't feel comfortable giving me your real email address, don't expect me to feel comfortable publishing your comment.

Website (optional):

Follow me on Twitter

Best Of

  • How not to apply for a job Applying for a job isn't that hard, but it does take some minimal effort and common sense.
  • Simplified Form Errors One of the most frustrating experiences on the Web is filling out forms. When mistakes are made, the user is often left guessing what they need to correct. We've taken an approach that shows the user in no uncertain terms what needs to be fixed.
  • The best of 2006 I wrote a lot of drivel in 2006. Here's the things that are less crappy than the rest.
  • Rounded corners in CSS There lots of ways to create rounded corners with CSS, but they always require lots of complex HTML and CSS. This is simpler.
  • Debunking predictions Read/Write Web's authors have some goofy predictions.
  • More of the best »

Recently Read

Get More

Subscribe | Archives

11

Recently

Physical camera shutter for Cisco Spark Board (Jul 6)
A 3d printable design for a camera shutter for a Cisco Spark Board
My Travel Coffee Setup (Jan 20)
What my travel coffee brewing setup looks like, and how you can build your own for under $100.
Turkey Legs (May 30)
Product naming gone awry.
Speaking for Geeks: Your Slides (Dec 17)
Tips and tricks for creating great slides.
Speaking for Geeks: Writing Your Talk (Dec 14)
Don’t wait until the night before the talk to write it. Crazy, I know.
Speaking for Geeks: Tell a Story (Dec 13)
Telling a story keeps your presentation focused, keeps your audience interested, and makes it easier for you to remember your talk.
Speaking for Geeks: Where to speak (Dec 11)
You've got a great idea for a talk. How do you find conferences to submit it to?
Speaking for Geeks: Getting your session accepted (Dec 10)
Your conference speaking submissions are not getting accepted because they're bad. Here's how to make them better.

Subscribe to this site's feed.

Elsewhere

Tropo
Voice and communications platforms, including Tropo and Phono. Work.
SacStarts
The Sacramento technology startup community.
Pinewood Freak
Pinewood Derby tips and tricks

Contact

Adam Kalsey

Mobile: 916.600.2497

Email: adam AT kalsey.com

AIM or Skype: akalsey

Resume

PGP Key

©1999-2017 Adam Kalsey.
Content management by Movable Type.