Web Services API Versioning

backwards-compatibilityversioningweb-serviceswsdl

I offer a small Web Services API to my clients which I plan to evolve over time. So I need some sort of versioning, but I can't find any information about how you do something like that.

Is there a best practice?

How can I keep adding new functionality without breaking compatibility with the web services consumers?

Best Solution

Versioning is a complex topic, so first, you need to define your goals in a more descriptive manner. It would be great to say that you have an interface insures you'll never break compatibility, but depending on what the new functionality is, that might not even be possible. So there are different situations and different trade-offs.

If your intent is to only provide new functionality to new consumers, and all of your consumers are direct consumers (no intermediaries, frameworks, etc.), then a discrete endpoint approach is the best choice. Each time you add a feature that risks a break, create a new endpoint, give it a new version number and then let the consumers know to validate against it and switch their configurations. This strategy is pretty tried and true, but it has the drawbacks of putting the burden on consumers to keep up to date. Also, if there are dependencies between services it can become a chore to track. The upside being if code breaks it's not (directly) your fault.

The other main strategy is the extensible interface. There's three different varieties here that I'm aware of. First, is the type of interface that tries to so well describe the service domain that every possible feature you might add is somehow possible given the existing interface. If that sounds hard, it is. You might call this the perfect interface. Everything is completely described, but the entire domain is also completely described. The "perfect" is really only on paper though.

The second variety is the type that looks like a normal interface but add generic extension points. In WSDLs this means xs:any, name-value pairs or something similar. You might call this the basic extensible interface. It's not too hard to do, but it's not without it's complications. The extension points may make the interface harder to work with in certain tooling (xs:any), or explicitly lose some of your ability to validate inputs and outputs (name-value pairs). It's also pretty easy to abuse those extension points in a way that makes the version 3 or 4 pretty hard to use.

The third variety is the type that converts your interface into a byte-stream. You might call these god interfaces. They aren't without their justifications, but if you're using one, you may want to ask why you're using web-services at all. Maybe you should be thinking about raw TCP/IP, or basic HTTP GET/POST. But maybe you're fed up with the complexity of WSDLs and XSDs and you just want to start from scratch but you're tied to web-services for some infrastructure reason. Realize however that once you start down this path, you're going to need a whole new way of describing to your consumers how to/not to use your service, and if you use XSD for that.. well you're basically back where you started.

Your best bet is to know all these options and approach your service design by first trying for the "perfect interface", then giving up and adding generic extensibility points. Trying to design the perfect interface will force you to learn things which will make your service better, not just your interface, but it will take time, and if you don't limit that time somehow, it'll take forever.

A little bit short of a true god interface, there is the wrapper interface. If you're system has layers, you want your interface to be in layers too. When you change layer B, you only want to change layer B, not all the instances in layer C.

Related Question