CINXE.COM
The importance of being versioned - Human Who Codes
<!DOCTYPE html> <html lang="en"> <head> <script async src="https://www.googletagmanager.com/gtag/js?id=G-DF11Y9MFRM"></script> <script>(function(){const analytics_id = "G-DF11Y9MFRM"; window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', analytics_id); })();</script> <!-- Global Metadata --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="icon" type="image/png" href="/favicon.png"> <meta name="generator" content="Astro v2.6.5"> <meta name="ttw" content="cfanq3r"> <!-- Primary Meta Tags --> <title>The importance of being versioned - Human Who Codes</title> <meta name="title" content="The importance of being versioned - Human Who Codes"> <meta name="description" content="The Official Web Site of Nicholas C. Zakas"> <!-- Canonical URLs --> <link rel="canonical" href="https://humanwhocodes.com/blog/2011/02/22/the-importance-of-being-versioned/"> <!-- Feeds --> <link rel="alternate" type="application/rss+xml" title="Human Who Codes - Blog" href="https://humanwhocodes.com/feeds/blog.xml"> <link rel="alternate" type="application/json" title="Human Who Codes - Blog" href="https://humanwhocodes.com/feeds/blog.json"> <link rel="alternate" type="application/rss+xml" title="Human Who Codes - Snippets" href="https://humanwhocodes.com/feeds/snippets.xml"> <link rel="alternate" type="application/json" title="Human Who Codes - Snippets" href="https://humanwhocodes.com/feeds/snippets.json"> <link rel="alternate" type="application/rss+xml" title="Human Who Codes - All" href="https://humanwhocodes.com/feeds/all.xml"> <link rel="alternate" type="application/json" title="Human Who Codes - All" href="https://humanwhocodes.com/feeds/all.json"> <!-- Open Graph / Facebook --> <meta property="og:type" content="website"> <meta property="og:url" content="https://humanwhocodes.com/blog/2011/02/22/the-importance-of-being-versioned/"> <meta property="og:title" content="The importance of being versioned - Human Who Codes"> <meta property="og:description" content="The Official Web Site of Nicholas C. Zakas"> <meta property="og:image" content="https://humanwhocodes.com/favicon.png"> <!-- Twitter --> <meta property="twitter:site" content="@humanwhocodes"> <meta property="twitter:creator" content="@slicknet"> <meta property="twitter:card" content="summary_large_image"> <meta property="twitter:url" content="https://humanwhocodes.com/blog/2011/02/22/the-importance-of-being-versioned/"> <meta property="twitter:title" content="The importance of being versioned - Human Who Codes"> <meta property="twitter:description" content="The Official Web Site of Nicholas C. Zakas"> <meta property="twitter:image" content="https://humanwhocodes.com/favicon.png"> <link rel="stylesheet" href="/_astro/_...slug_.c4d39581.css" /> <link rel="stylesheet" href="/_astro/about.7a05c7cf.css" /></head> <body itemscope itemtype="http://schema.org/WebPage"> <header class="highlight-background"> <nav role="navigation" class="page-width center center-text gutters collapsible-corners"> <h1 class="no-margin"><a href="/"><img src="/_astro/logo-full-web.fbbbde18.svg" alt="Human Who Codes" height="50"></a></h1> <ul class="inline-list inline-spaced-list center-text-on-small-screens overflow-x-scroll all-caps bold"> <li class="hide-offscreen"><a href="#content">Skip to content</a></li> <li><a href="/books/" class="dark-text no-underline">Books</a></li> <li><a href="/reading/" class="dark-text no-underline">Reading</a></li> <li><a href="/coaching/" class="dark-text no-underline">Coaching</a></li> <li><a href="/newsletter/" class="dark-text no-underline">Newsletter</a></li> <!-- <li><a href="/speaking/" class="dark-text no-underline">Speaking</a></li> --> <li><a href="/donate/" class="dark-text no-underline">Donate</a></li> <li><a href="/contact/" class="dark-text no-underline">Contact</a></li> </ul> </nav> </header> <hr> <div class="content-background"> <div id="page-grid" class="page-width page-grid center"> <main id="content" role="main" class="content-width gutters"> <article itemtype="http://schema.org/Article"> <header> <h1 itemprop="headline" class="no-margin gutter-bottom headline-text">The importance of being versioned</h1> <p itemprop="description" class="no-margin-top"></p> <div class="post-meta gutter-top smaller-font dark-dotted-border-top dark-dotted-border-bottom"> <p class="no-margin byline">Posted at <time datetime="Tue, 22 Feb 2011 00:00:00 GMT" itemprop="datePublished">February 22, 2011</time> by <span itemprop="author" itemtype="https://schema.org/Person">Nicholas C. Zakas</span></p> <p class="no-margin-top tags">Tags: <a href="/blog/tag/api" rel="tag">API</a><span>, </span><a href="/blog/tag/versioning" rel="tag">Versioning</a><span>, </span><a href="/blog/tag/web-services" rel="tag">Web Services</a><span></span> </p> </div> </header> <section id="post-body" class="content-font"> <p>If you write or use a public web service, please read this post carefully. I’m shocked and saddened at just how poorly many of these APIs are designed. I’m not necessarily talking about the choice of REST or not, or XML vs. JSON, as these are somewhat matters of preference and usage patterns. I’m talking about whether or not the API is versioned.</p> <h2 id="what-is-a-versioned-api">What is a versioned API?</h2> <p>A versioned API is one where you can select the version that your site consumes. As a very simple example, consider YUI. The most recent version is YUI 3.3.0 and can be included in your page using the following code snippet:</p> <pre><script src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script></pre> <p>Note the embedding of the version in the URL – this is how YUI handles API versioning. That means you can choose to use an earlier version, say YUI 3.1.0 by using this code instead:</p> <pre><script src="http://yui.yahooapis.com/3.1.0/build/yui/yui-min.js"></script></pre> <p>Many web services use a similar methodology, either providing the version number in the URL or as a parameter to the API.</p> <h2 id="why-versioned-apis-are-important">Why versioned APIs are important</h2> <p>A versioned API is a contract between the producer of the API and its consumers saying, “I guarantee that this API will continue to work this way for the foreseeable future.” Put simply, if <code>api(2, 3)</code> returns 5 now, it will always return 5. And that’s the number 5, not a string “5″, or a JSON object <code>{ value: 5 }</code>. Of course, not all APIs are this simple.</p> <p>Realistically, APIs need to change. Bugs need to be fixed, security holes closed, out-of-date schemas updated, and so on. You absolutely cannot expect an API to never change. It’s how you manage these changes that makes all the difference to consumers. Versioned APIs provide the ability to make <em>breaking changes</em> without breaking already-existing implementations.</p> <p>Consider an API that is called by your site to embed a list of articles from a RSS feed. When you test, the API returns HTML as an ordered list with a class name of “rss-list”. You write your CSS to style the list appropriately. Your integration server is setup and verified by your QA team and the site is pushed live. The next day, the layout in production is completely broken. What happened? The API was changed to return JSON instead of HTML, as the API author believed it was inappropriate to force markup on the API consumers. While that may be a rational API design decision (though arguably one that should have been made early on), it’s irresponsible to make such a dramatic change to an API that others are using in production. Congratulations, you just broke the Internet.</p> <p>A versioned API allows API producers to make those changes whenever you want. Will the change break code already in use? Just change the version. Whether it’s a minor point release or a major point release, just introducing the new version allows the API to continue to evolve while not breaking existing implementations. You can then notify the API consumers that there is a new version available and they can schedule an upgrade to use the new API version. The API consumers then can go through their normal integration and testing cycle to ensure that what goes out into production is fully functional.</p> <h2 id="managing-versions">Managing versions</h2> <p>There are a fair amount of decisions that have to be made when providing a versioned API. The most important decision is how to determine when the version should change. To be clear, not all API changes require a version change. Here’s the key determinant for a new version: are you changing the functionality in such a way that breaks current implementations? If the answer is yes, then it’s time for a new version; if no, then a new version isn’t necessary.</p> <p>For example, consider an API that fetches article text. This API is experiencing problems returning data so that 50% of the time an empty string is returned. It’s unlikely that the API consumers are relying on this behavior so improving the rate at which actual article contents are returned doesn’t require a version change.</p> <p>Schema changes can be tricky, both for input parameters and response formats. Adding additional optional parameters may not require a version change. The same can be said for adding additional fields in the response format. If you add a new required input parameter or change the name of a field in the response format, then a new version is required.</p> <p>Bug fixes may or may not require a version change based on the scope of the change. Feature changes almost always require a version change – this includes adding new features and removing or altering existing features. To repeat: the key determinant is if the change you’re making breaks current implementations.</p> <h2 id="supporting-past-versions">Supporting past versions</h2> <p>Just because your API is versioned doesn’t mean you need to continue to support all versions ever created. The correct rules for managing versions depend largely on the API itself, how frequently the API changes, and for how long you want to support old versions. The rules for JavaScript APIs are different than for web service APIs. There are, however, some general guidelines that you can start with:</p> <ul> <li>Keep track of your API consumers. You may want to require an API key for use and tie that to a verified email address.</li> <li>Plan to maintain at least two previous versions of the API.</li> <li>The API should be backwards compatible for at least one version. That means parts of the API can be deprecated immediately but shouldn’t be removed immediately.</li> <li>Each previous version should be supported (still available, but not under active development) for a minimum of six months. This gives consumers enough time to upgrade.</li> <li>When a new version is released, notify the consumers (via email if you have an API key) and inform them of the timeframe for upgrade. The timeframe must be in months – many companies plan at least a couple months ahead of time.</li> <li>Monitor usage of older versions. When you get within one month of end-of-life for a version, notify those consumers that are still using that version to give them fair warning. Do the same two weeks later.</li> </ul> <p>Keeping API consumers informed of changes to the API is the most important aspect of these guidelines. No one likes it when their site worked yesterday and doesn’t work today – especially when they didn’t make any changes.</p> <p>You’ll note that not all APIs have API keys, such as JavaScript libraries. Whether or not you use one is entirely dependent on whether or not you want to track API usage by consumers. If there’s no advantage to doing so, then you may not use API keys – you’ll just need to find some way to communicate with consumers about version changes.</p> <h2 id="conclusion">Conclusion</h2> <p>The example I used earlier was for YUI, but this article also applies to any web services you may consume or produce. If you’re providing a public-facing API, please ensure that it’s versioned. If you’re considering using a public-facing API, inoculate yourself from random and unexpected errors by using only versioned APIs. There are too many companies that still insist on providing unversioned APIs for public consumption. These APIs put a tremendous burden on development and testing teams that is unfair and prevents their sites from being as reliable as possible. Give them that feedback – you’ll be doing yourself and all other API consumers a great service.</p> </section> </article> <div class="grid-columns round-borders content-item-border highlight-background"> <div class="gutters"> <!-- <h2 class="no-margin-top">Free E-book!</h2> --> <p><a href="https://ebooks.humanwhocodes.com/interrupt-rate" target="_blank"><img src="/images/books/interrupt-rate.png" alt="Managing Your Interrupt Rate as a Tech Lead E-book Cover" height="250"></a></p> <p>Take control of your calendar to get more done! The popular blog post series plus frequently asked questions all in one convenient PDF.</p> </div> <div class="gutters"> <h2 class="no-margin-top">Download the Free E-book!</h2> <p><i>Managing Your Interrupt Rate as a Tech Lead</i> is a free download that arrives in minutes.</p> <form method="post" name="sideemailform" action="https://mailinglist.humanwhocodes.com/api/subscribe"> <div id="mc_embed_signup_scroll"> <div style="margin-bottom: 0.5em"> <label>First name: <input type="text" value="" style="width:100%" name="firstName"> </label> </div> <div> <label>Email address: <input type="email" value="" style="width:100%" name="email" required=""> </label> </div> <input type="hidden" name="formId" value="5426991"> <div class="center-text gutters"> <input type="submit" value="Send my E-book"> </div> </div> </form> </div> </div> </main> <div id="sidebar" class="sidebar-width sidebar-background gutters hide-on-small-screens"> <h1 class="hide-offscreen">Additional Information</h1> <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CKYIEK3Y&placement=humanwhocodescom" id="_carbonads_js"></script> <h2 class="smaller-font">My Books</h2> <ul class="inline-list inline-image-list"> <li><a href="https://www.lulu.com/en/us/shop/nicholas-c-zakas/understanding-javascript-promises/paperback/product-2yvnqn.html"><img src="/images/books/promises.png" alt="Understanding JavaScript Promises" width="100"></a></li><li><a href="https://geni.us/hwc-es6-book"><img src="/images/books/understandinges6ns.png" alt="Understanding ECMAScript 6" width="100"></a></li><li><a href="https://geni.us/hwc-oopjs-book"><img src="/images/books/oopinjsns.png" alt="The Principles of Object-Oriented JavaScript" width="100"></a></li><li><a href="https://geni.us/hwc-mjs-book"><img src="/images/books/maintainablejs.png" alt="Maintainable JavaScript" width="100"></a></li> </ul> <h2 class="smaller-font">Recent Snippets</h2> <ul> <li><a href="/snippets/2024/03/publishing-to-jsr-release-please/">Publishing to JSR using release-please</a></li><li><a href="/snippets/2023/11/how-to-setup-known-hosts-jenkins-pipeline/">How to setup a known_hosts file for a Jenkins pipeline job</a></li><li><a href="/snippets/2023/01/mimicking-dirname-filename-nodejs-esm/">Mimicking __dirname and __filename in ESM modules in Node.js</a></li><li><a href="/snippets/2022/02/eleventy-npm-modules-client/">How to add npm packages for client-side use in Eleventy</a></li><li><a href="/snippets/2021/03/create-user-linux-ssh-key/">Creating a new user with an SSH key on Linux</a></li><li><a href="/snippets/2021/02/how-to-setup-deploy-web-application-dokku/">How to setup and deploy a web application on Dokku</a></li><li><a href="/snippets/2021/02/how-to-regain-jenkins-web-access-after-lockout/">How to regain Jenkins web access after being locked out</a></li><li><a href="/snippets/2020/10/create-typescript-declarations-from-javascript-jsdoc/">Create TypeScript declarations from JavaScript and JSDoc</a></li><li><a href="/snippets/2020/10/read-environment-variables-deno/">How to read environment variables in Deno using JavaScript</a></li><li><a href="/snippets/2020/08/validate-github-webhook-signature-nodejs/">How to validate the signature of a GitHub webhook using Node.js</a></li> </ul> <h2 class="smaller-font">Archives (20 Years)</h2> <ul> <li><a href="/blog/2024/">2024</a></li><li><a href="/blog/2023/">2023</a></li><li><a href="/blog/2022/">2022</a></li><li><a href="/blog/2021/">2021</a></li><li><a href="/blog/2020/">2020</a></li><li><a href="/blog/2019/">2019</a></li><li><a href="/blog/2018/">2018</a></li><li><a href="/blog/2016/">2016</a></li><li><a href="/blog/2015/">2015</a></li><li><a href="/blog/2014/">2014</a></li><li><a href="/blog/2013/">2013</a></li><li><a href="/blog/2012/">2012</a></li><li><a href="/blog/2011/">2011</a></li><li><a href="/blog/2010/">2010</a></li><li><a href="/blog/2009/">2009</a></li><li><a href="/blog/2008/">2008</a></li><li><a href="/blog/2007/">2007</a></li><li><a href="/blog/2006/">2006</a></li><li><a href="/blog/2005/">2005</a></li><li><a href="/blog/2004/">2004</a></li> </ul> </div> </div> </div> <hr> <footer class="inverted-colors"> <div class="page-width center"> <div class="page-grid orange-border-bottom"> <div class="margin-top content-width gutters"> <div class="collapsible-media-box"> <div class="media-box-media center-text"> <img src="/_astro/me-150x150.0969500a.jpg" alt="Photo of Nicholas C. Zakas" width="150" class="circle-image"> </div> <div> <h2 class="no-margin-top center-text-on-mobile">About the Human</h2> <p>Hi, I'm Nicholas C. Zakas, an independent software developer living in Mountain View, California. I've been a software architect at companies like Yahoo and Box, as well as an author and speaker. I created the <a href="https://eslint.org">ESLint</a> open source project and wrote several <a href="https://humanwhocodes.com/books">books</a>. At the moment, I'm <a href="https://humanwhocodes.com/blog/2014/04/02/i-have-lyme-disease/">recovering from Lyme disease</a> and haven't been able to leave my home much in the past five years. (<a href="https://medium.com/lyme-disease-warrior/progress-report-october-2018-fc38d4769e65">Health update</a>, <a rel="me" href="/about">More about me</a>)</p> </div> </div> </div> <div class="margin-top sidebar-width hide-on-small-screens"> <h2 class="no-margin-top">On the Web</h2> <ul> <li><a href="https://fosstodon.org/@nzakas" rel="me">Mastodon</a></li> <li><a href="https://www.twitter.com/slicknet/">Twitter</a></li> <li><a href="https://www.github.com/nzakas/">GitHub</a></li> <li><a href="https://www.instagram.com/humanwhocodes">Instagram</a></li> <li><a href="https://www.youtube.com/channel/UC95Pwj8oPPZN2mJCEtMqOsg">YouTube</a></li> <li><a href="https://www.linkedin.com/in/nzakas">LinkedIn</a></li> <li><a href="https://www.slideshare.net/nzakas/presentations/">Slideshare</a></li> <li><a href="https://amazon.com/author/nzakas/">Amazon</a></li> </ul> </div> </div> <p class="center-text"><a href="/policies/privacy">Privacy Policy</a> | <a href="/policies/terms">Terms of Service</a></p> <p class="center-text">Copyright © 2020-2024 Human Who Codes LLC. Content licensed under a <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/" rel="nofollow noopener">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License</a>.<br>Some links may be affiliate links. We may get paid if you buy something or take an action after clicking one of these. As an Amazon Associate we earn from qualifying purchases. <a href="/feeds/blog.xml">Blog Feed</a></p> </div> </footer> </body></html>