Some people, when confronted with a problem, think “I know, I’ll use versioning.” Now they have 2.1.0 problems.
If your software has a fuzzy or seemingly random versioning scheme — or no apparent version number at all — you’ll likely agree it can be a nightmare to work with.
If this is your reality, you’re probably dealing with questions like: Is this backwards compatible with the previous version? Is there new major functionality I need to be aware of? Why does this appear to be an update although the version number hasn’t changed? Without clear and simple answers, these questions can cause headaches and loss of sleep.
Versioning schemes like Semantic Versioning are therefore hailed by software professionals for being clearly defined and intuitive. Having a good versioning scheme makes life easier for everyone.
For more than 60 years — at least since Fortran II was made available in 1958 — the discipline of software versioning has been ingrained into software development culture. Having software without a version number or version moniker is almost unthinkable. Software versioning as a phenomenon is so ubiquitous that even things that aren’t software, like PR 2.0, gov2.0 and Tax 2.0, have “version” numbers.
APIs being software, most APIs have version numbers too. For libraries that are statically linked at compile time, this makes a lot of sense. You develop your client application in accordance to a clearly defined API, link to the version number of the API you developed against, and you have the confidence that the integration is going to work until you upgrade the library.
Web API Versioning Has Unique Concerns
API, short for Application Programming Interface, is a set of clearly defined methods of communication between various software components. While usually being associated with software libraries, frameworks and operating systems, “API” is also used to describe programmable interfaces across network boundaries, such as remote procedure calls and most importantly; web APIs.
Since web APIs are seemingly “just APIs on the web”, the discipline of versioning web APIs has become the norm as well. But there’s one important difference between web APIs and the API of a software library: Web APIs aren’t statically linked at compile time. Since web APIs are hosted on a server, that server needs to preserve backwards compatibility for as long as a given version of the API is used.
Statically linked software libraries don’t have this predicament. For statically linked software, the fact that you linked against v1.0 of a library does not force the maintainers of that library to support v1.0 in any way. Your usage of v1.0 does not incur any cost on the maintainers of the library. The maintainers can delete every line of code you’re dependent on from their source code repository without causing any harm or breakage. In the same vein, when v2.0 is released, that does not force you to upgrade. The library maintainer’s v2.0 release does not incur any cost on you. You can continue using v1.0 for as long as you wish.
This world of decoupled duality does not exist for web APIs, though. As web APIs evolve, each prior version needs to be actively maintained for as long as that version of the web API is in use by a client. Web APIs can be globally distributed web services, dynamically adapting to their clients, each potentially integrated against a different version of the web API definition. With all these unique traits, their differences start to significantly outweigh their likeness to statically linked software library APIs.
Web APIs Are More Similar to Websites
Both web APIs and static library APIs are software, but everything from how they are developed and deployed to how they are hosted and served is completely different. Perhaps all of these differences warrant a different perspective on how they are versioned as well?
In many ways, a web API has more in common with a web site than to a statically linked software library. And when was the last time you saw a website with a version number? When you make a backwards incompatible change in your API, have you ever considered the fact that you might not be creating a new version of the same API, but an entirely new API altogether? As Roy Fielding expressed in his 2014 interview with Mike Amundsen:
What you are creating is not a new version of the API, but a new system with a new brand. On the Web, we call that a new website. Websites don’t come with version numbers attached because they never need to. Neither should a RESTful API. A RESTful API is just a website for clients with a limited vocabulary.
The Costs of Versioning
As the code that culminates into an old version of a web API can’t be deleted without breaking clients, the existence of that code has a cost. There’s a higher maintenance cost, because a versioned codebase is a larger codebase. Each version of your API needs to be independently developed, patched, documented and deployed. Broad-stroke API versioning will even affect resources that haven’t changed, creating an exponentially larger API surface to maintain than a more fine-grained strategy.
If all versions share the same codebase, developers must consider all versions when touching any part of the code, making the code harder to understand. This can cause bugs and slow down development. All of this leads to discontented, less productive and less engaged developers. Negative morale can have a huge cost if not addressed.
There’s a more concrete and measurable cost than losing developer faith, though. In 2013, Jacques Dubray wrote an article that groups web API versioning strategies into three different categories (Knot, Point-to-Point, and Compatible) and a formula for how to measure the cost over time in each category. What Dubray found was that point-to-point versioning, which is the strategy employed by most web API developers today, is 45% more costly with 4 different API versions than a Compatible Versioning strategy. While Compatible Versioning has a higher initial cost, over time, it provides huge cost savings.
Since version numbers hide the fact that the new API does not support the features of the old one, there’s little incentive to figure out how to deal with breaking changes other than minting a new version number. And for the same reason, there’s no incentive to figure out answers to questions like how customers are notified of changes, how they are incentivized to upgrade or how we measure which features the customers are using. And as most weathered developers know, the longer we postpone questions like these, the more expensive they become to answer. We should therefore attempt to find an answer early, rather than late.
A Change of Strategy
In his great API Change Management blog post, Zdenek Nemec writes:
Versioning an API is like having your age in your name. Yes, I’m talking to you
Emmanuel46. And then comes the fallacy of “nested” resources: If the resource
/john32) has nested resource
/john32/child), is the
childresource of version 32 as well? Or is it a
Johnwas at version 32? What if the
childis changing versions regardless of
Due to the issues pointed out by Nemec and in this article so far, an echo and extension of Nemec’s proposal would therefore be that you scrap your simplistic versioning strategy, because as Ben Morris’ writes; the version number itself is a red herring. Instead of a Versioning Strategy, you should have a Change Strategy.
A Change Strategy embraces the Compatible Versioning Strategy mentioned above, by always being backwards compatible without needless duplication. Consequently the Robustness Principle will also be incorporated, giving you a solid foundation for introducing changes to your API. To implement a Change Strategy, you need to be able to answer the following five questions:
- What to version?
- What are the extension rules?
- How do we introduce breaking changes?
- How do we monitor feature usage?
- What’s our communication plan?
1. What to version?
In outlining his API Change Management theories, Nemec answers this question as follows:
- The client has a version
- The message format has a version
- The API implementation (server) has a version
- The documentation (API description) has a version
- Resources don’t have a version
- Relations between resources don’t have a version
- The API itself doesn’t have a version
2. What are the extension rules?
Nemec has an answer for this question as well, repeated for brevity:
- You must not take anything away
- You must not change processing rules
- You must not make optional things required
- Anything you add must be optional
This list might change if your API is using hypermedia, in which case point 3 and 4 can be circumvented. By adding default values (think
<input type="hidden">) in the form describing the request, a client unaware of new and required properties will just blissfully pass the default values on in the request.
3. How do we introduce breaking changes?
Nemec has an answer for this question as well, again for brevity; if a change to either of the following violate the extension rules listed earlier, you simply need to create a new resource:
- Resource Identifier (the URI) including any query parameters and their semantics.
- Resource metadata (such as the HTTP headers).
- Resource data (such as the HTTP body) fields and their semantics.
- Actions the resource affords (e.g., available HTTP Methods).
- Relations with other resources (e.g., Links).
If the message format itself changes, you can use content negotiation to serve the new version to new clients and the old version to old clients.
4. How do we monitor feature usage?
Since statically linked software libraries have no server component, it’s impossible to know which parts of the API it exposes are in use and which are not. Since web APIs do have a server component, it’s both possible and really smart to use that advantage to monitor which features of your API are in use.
Monitoring is useful information for the business side of your organization to prioritize time spent on adding to and maintaining each feature. But it is crucial information to have when considering deprecating API endpoints.
HTTP server logs are great and easily accessible source of information about feature usage in your API, especially if you’re using hypermedia extensively, because you’ll have more links and resources in your API, giving you more details about what’s going on. The more resources, the more information.
As the default HTTP server logs only contain the request URI, a few headers, the response status code, and client IP address, at some point they will be too shallow to provide you the rich information you require to make sound decisions about the future of your API. Adding custom logging through infrastructure like reverse proxies, API management software or simple log statements in your code will provide you with all the information you want.
5. What’s our communication plan?
The last question of your Change Strategy relates to how you communicate with the customers of your API. When you change your API you should have a clear plan on how to communicate the change.
Every company, API, and customer is different, so you need to figure out a method of communication that works for you. It can be anything from a newsletter, a public Slack channel, a dashboard the customer sees regularly, the API documentation, or other resources.
Regardless of your method, having a plan to communicate new features and breaking changes with API customers is essential. Something as simple as email notifications — no matter how obvious and mundane it might seem — are imperative for upfront communication to avoid last minute issues.
Change Management in Practice
Now that the theory should be well established, how does Change Management work in practice? Let’s take a fictive API request as an example:
POST /nordic-apis/2018 HTTP/1.1
"from": "Nordic APIs Platform Summit",
Imagine that this API request has been out in the wild for a few months and now has hundreds of active clients. Then you notice the typo:
aquire is missing a
c! What do we do? Panic! No, calm down. Change Strategy to the rescue!
- Add support for the correct spelling of acquire to the API.
- Fix the spelling in the documentation. The fixed spelling can be added either in place of the typo or as a new field, marking the old one as deprecated.
- Notify the customers of the typo and that they should update their client software.
- Add monitoring of the usage of the typo field.
- Time passes
- Notify customers still using the typo field.
- More time passes
- Incentivise the customers still using the typo field
- With Money
- Plan upgrade
- Free products
- The point here is that keeping old code around costs money.
- And that’s money better spend at making your customer happy than your developers unhappy.
- Lastly we can remove the typo field from the API.
- Making the code lean and both customers and developers happy.
Final Thoughts on Smart API Change Strategy
Web APIs are inherently unique, functioning more like websites than your typical static library API. Therefore, before designing your APIs with the mindset of breaking change, consider the impact on the client ecosystem. Rather than a traditional Point-to-Point versioning strategy, Compatible Versioning can help avoid losing developer faith and be used to maintain efficient development techniques.
To sum things up, consider the five aspects of smart API change management: Know what you are versioning, have rules in place for extending resources, try to create new resources rather than introducing breaking change, monitor feature usages, and have a communication plan with the consumers of your API. With answers to these tough questions in place, you’ll be set to scale your API ecosystem with confidence.
There are many opinions on the topic of versioning, and we’d love to hear yours. What are your thoughts on this proposed Change Strategy? Have you adopted a similar technique in your API? Let us know in the comments below.