Simultaneous Platform-Wide Versioning: How to Implement API to SDK Synchronicity Kristopher Sandoval January 5, 2016 In the API realm, one of the most rewarding practices a developer can undertake is to unify their system functionality. Having disparate updates, library versioning, and documentation can harm the user through confusion and obsolescence, can harm the provider with rough updates, and can harm the API itself through low adoption and retention rates. It’s far better to have everything in sync. Implementing simultaneous platform-wide versioning eliminates much of the synchronization pains involved in hosting an API. This is a process of keeping your entire system constant in terms of updates, documentation, and libraries. The end result improves user experience, security, and increases economic potential. In this piece, we’re going to discuss exactly what the difference between an API and SDK is, what versioning is, and how it affects the user space. Additionally, we’ll take an in-depth look at how smart versioning affects the user experience and security index of an API, and how to implement this synchronicity seamlessly. Defining Versioning Versioning is the process by which a system is updated, with these updates being recorded historically on a server or client to allow for backdating previous revisions. You can tell when versioning is part of the development cycle when an API, program, or service states their version number, often 0.01–0.99 for beta and alpha builds, then version 1.0 and above for release or public builds. The benefits behind a versioning system are vast. First and foremost, versioning is a source control tool. We’ve already talked about source control, but it bears repeating — being able to unify the user experience behind a single, official release, allows you to track bugs more effectively, develop new features with greater ease, and ensure a cohesive experience across multiple properties. A good deal of added benefit comes from this strict source control: Synchronizing versions allows you to stay within the confines of the strict laws concerning privacy across the world by ensuring all users are utilizing a system that is up-to-date with internal revisions, minimizing your risk as a developer. Keeping versions unified prevents users from utilizing previous, less secure releases, which in turn reduces the chance of reverse engineering and general “hacking” of your service and system. Allows for more stringent and accurate documentation, the core backbone of any effective API Aids in keeping the feature set up to date for all API consumers. Related: What Languages Should My Helper Libraries Support? Versioning as UX – A Case Study Let’s look at a real-world example of how important versioning, and by extension API to SDK synchronicity, really is. A successful versioning system intrinsically means it won’t be noticed, so let’s view a system that failed. In August of 2013, security vendor TrendMicro detailed an exploit in Java that cracked the security of the entire ecosystem. The exploit targeted CVE–2013–2463, which allowed remote attacks to affect the CIA of a system (CIA standing for confidentiality, integrity, and availabilty, the standard explanation of security for network integrated systems). The big problems with this exploit were what system it affected, and what userbase it affected. Confined to Java 6, an older version of Java, the vendor left the issue unpatched, as support for that version had ended. However, at that at the time, almost 50% of Java users utilized Java 6 for their system. Support might have ended, but usage had not. Due to a failure in versioning support, and more specifically in unification of patching, the vendor left a huge exploit wide open, affecting 50% of the total user base. Over time, third party solutions cropped up, but the fact that the issue existed at all is a testament to how important the concept of versioning is. For a more in-depth example of where versioning has failed, see our piece titled Zero Day Flash Exploits, Versioning, and the API Space. Love and Marriage – Joining APIs and SDKs So given how fundamentally important version unification is, you may wonder how exactly you can tie in synchronicity. There are a few approaches, and they are largely divided into three camps of thinking. How you code, what you present your systems through, and how they are utilized will determine which approach is best. What is the Difference between an API and an SDK? Before we dive into the various approaches to marrying APIs and SDKs, we must first understand what these terms mean. An API (Application Program Interface) is the interface that allows software developers to write programs. It is a set of protocols that define how services and systems should interact. An SDK (Software Development Toolkit) goes one step beyond an API, usually making it easier and faster for developers to work. Often supplying code libraries, reference applications, and documentation, SDKs are helpful toolkits composed of all the tools and APIs necessary to build an application or microservice. These definitions often overlap, which can make differentiating the two difficult. The best way to understand it is to think of that age old math adage “every square is a rectangle, but not every rectangle is a square.” In our case, every SDK is an API, but not every API is an SDK. For a real-world example, look at the Java SDK/API suite. The API is a collection of all the languages used by Java to compile and run given sets of code. The SDK on the other hand contains the API itself, as well as the compiler, the runtime, and the various miscellaneous services and hooks that need to tie into the system. So, given their overlap and often disparate purposes, how do we marry SDKs and APIs? Here are some approaches. 1: Synchronicity Through a Unified Ecosystem The unified ecosystem is deceptively simple — push out a single native application, where the SDK and API are one and the same, with a central server handling versioning. This is the common approach for games and many cross-platform applications. It’s relatively simple to handle, but is effective strictly in a singular cross-platform situation. As an example, imagine we develop a budgeting application that uses an API server to handle computations and synchronize file revisions from device to device. When constructing our API, we unify by having the application native code wrapped by device specific code utilizing an additional service or API. An example of this type of synchronicity is the Under Armour API. By wrapping native code in a wrapper for both iOS and Android, a singular application or API utilizing the Under Armour API can be versioned on devices utilizing the same, central application. 2: Synchronicity Through Parallel Updating Interestingly enough, the Under Armour API itself follows a different approach to synchronicity than that which it provides to other applications and APIs. A quick look at their versioning policy shows a strategy set in parallel updating. Parallel updating may not seem like synchronicity at first glance — after all, in this strategy, an API may be several versions removed from the SDK, and the differences therein might be vastly different between the two. Synchronicity does not have to be a one-to-one relationship, however — all synchronicity requires is that the vendor manages changes jointly in some manner. Accordingly, the Under Armour versioning policy sets the following requirements: All API resources have the same version and will be incremented together Keep the version unchanged when introducing a non-breaking change Increment the minor version (e.g. 7.0 to 7.1) when introducing a breaking change Increment the major version (e.g. 7.1 to 8.0) when introducing substantial functionality Version APIs and SDKs independently, e.g. V7.0 API is encapsulated in V2.0 of SDK Allow multiple versions of APIs or SDKs with different functionality to exist This strategy is brilliant in its execution: By requiring API resources to be incremented together, we create a situation in which all APIs are versioned dependent on one another, ensuring the systems that communicate with one another are always synchronized. Incrementing separately for versions that introduce both breaking changes to core functionality and additional useful functionality allows users to opt-in to new features and systems while retaining the core distribution, and thus security, of the core API. Encapsulating separately versioned SDKs with versioned API increments allows for synchronicity between SDK versions internally, while keeping only the most relevant SDK data packaged with the most relevant API. Allowing different versions of APIs and SDKs to exist, as long as their functionality is different, allows synchronicity between APIs and SDKs on a user basis, eliminating developer overhead in that part of the process. 3: Synchronicity Through Serial Updating An additional solution can be found diametrically opposed to the parallel updating of Under Armour. In serial updating, both the SDK and API are simultaneously updated, and released in a serial version. For example, let’s imagine an API called APIu. This API is a unification API for server computations for games, processing systems, and SaaS providers. APIu as an API has its own version hierarchy, and accordingly, the SDK, known as SDKu, has its own as well. As the API is developed through 1.0, the SDK is updated through 1.0 as well. As the two are updated, a simple rule is followed — do not update the SDK unless the API is updating as well, and vice versa. Over time, you end up with a system that looks a lot like this: … API v1.0 – SDK v1.0 API v2.0 – SDK v2.0 … Updating serially has a few major benefits. For one, there is no messing about with different increments and variations on the base API and SDK. Additionally, it grants far more control, as every API release is vetted against the SDK release, and integration is ensured. There’s one HUGE drawback, however — it’s incredibly slow. Parallel updating allows for rapid development, as the SDK and API are developed separately and incremented to allow for experimental and possibly feature-breaking changes. While this makes the system more complicated, it does make it far more rapid compared to serial updating, which is slow and cumbersome. What is Your Development Strategy? Read: 3 Strategies for Developing Microservices Third Party Solutions As always, however, there is a bevvy of assorted third party solutions. These solutions take the existent API and generate an SDK from the code. This is great for developers in terms of versioning, as it utilizes a strict source in the form of the API base to generate a perfectly unified SDK. One great example of this kind of solution is RESTUnited. By utilizing a simple generator, RESTUnited is able to generate SDK REST API libraries in PHP, Python, Ruby, ActionScript, C#, Android, Objective-C, Scala, and Java. If a developer were to purposely create these SDKs, a lot of time and error would be required, and versioning would be a pain to undertake. By generating this code using such a service, however, the SDK can be kept perfectly in-version with the API — after all, the SDK in this case directly derives from the API, meaning that it, by design, has to be integrated in-version. Similar to RESTUnited, APImatic is another SDK generation service. The prime difference here, however, is that APImatic is arguably more flexible than RESTUnited, utilizing several additional feature-sets to allow for customizable SDK generation and more flexible constraints therein. The Problem with Generated SDKs While auto-generation of SDKs might seem like a wonderful prospect, the truth is that there’s a lot of problems with this approach when compared to hand-coded SDKs. Most glaringly, the fact is that SDK generation requires your API to be functionally perfect. Missing model definitions, lacking error codes, and more could cause incorrect SDK definitions. While this may have little impact on the API, in an SDK, it could make the entire document useless. Code generation is a mixed bag in the first place. Because there is no industry standard design approach accepted by API developers (though significant headway in this direction has been made by groups such as Open API Initiative), SDK generators have to use common assumptions and go from there, rather than developing specific SDK implementations given the API rigors. This leads to a general, rather than specific, oriented SDK. All of this may be reason enough to consider one of the previously mentioned versioning standards integrated with created SDKs; if your team is comfortable with their design however, and it has been vetted against common design principles, SDK generation might be an acceptable solution. Conclusion Fundamentally speaking, the issue at hand isn’t about keeping synchronicity between versions, but rather, at a higher level, unifying the experience of your user base and providing an ecosystem of security. While versioning and synchronicity is certainly a part of that, the fact is that if you follow a consistent documentation method, adhere to design specifications, and code at a high quality, much of the previously mentioned approaches will come naturally. We’ve said many times before that a system is only as secure as its weakest part — this comes through in user experience, as well. The user experience is only as good as its weakest part, and allowing your experience to drift because of simple differences in versions is arguably one of the easiest things to correct in the vast world of possible failures in the API space.