Need someone to lead product or development at your software company? I lead product and engineering teams and I'm looking for my next opportunity. Check out my resume and get in touch.

Versioning web services

Freshness Warning
This article is over 14 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.

This discussion has been closed.

Recently Written

A framework for onboarding new employees (May 15)
There’s no single good way to onboard an employee that works for every role. Here's a framework for creating a process that you can adapt to each situation.
TV hosts as a guide for software managers (May 10)
Software managers can learn a lot from journalists or late night TV hosts and how they interview people.
The Improvement Flywheel (Apr 29)
An incredible flywheel for the improvement of a development team. Fix a few things, and everything starts getting better.
Managers and technical ability (Dec 26)
In technical fields, the closer you are to the actual work being done, the closer your skills need to resemble those of the people doing the work.
Dysfunctions of output-oriented software teams (Sep 17)
Whatever you call it, the symptom is that you're measuring your progress by how much you build and deliver instead of measuring success by the amount of customer value you create.
Evaluative and generative product development (Aug 30)
Customers never even talk to the companies that don't fit their needs at all. If the only product ideas you're considering are those that meet the needs of your current customers, then you're only going to find new customers that look exactly like your current customers.
Product Manager Career Ladder (Aug 19)
What are the steps along the product management career path?
Building the Customer-Informed Product (Aug 15)
Strong products aren't composed of a list of features dictated by customers. They are guided by strong visions, and the execution of that vision is the primary focus of product development.

Older...

What I'm Reading

Contact

Adam Kalsey

+1 916 600 2497

Resume

Public Key

© 1999-2020 Adam Kalsey.