API Versioning in the Cloud. Presented to the Galvanize gSchool on 6/14/2013 by Travis McChesney, Senior Engineer- Cloud Elements. Content Negotiation, URI, URI Parameter, Cloud Elements Demo.
20. URI
• Version number considerations
• [Major].[Minor].[Revision] (e.g. v1.5.1)
• Major:
• Significant business rule changes
• Fundamental API changes
• Minor:
• Change of representation (moving from
"recipient" to "recipient-email")
• Revision: Property addition (adding "priority")
30. Your Super Cool App
Cloud Elements
CE Messaging API
SendGrid
TwilioTwilio API
SendGrid API
Hinweis der Redaktion
As you know, APIs aren’t just web based. It’s just an Application Programming Interface.At my previous job I worked with non-web-based APIs. There was a large program called Facets (an insurance payer program written in C++), and I would use the exposed API to create extensions (written in C#) that execute custom business logic. So, in this case, we were mixing languages, and the exposed API made it possible (through COM).
In object oriented design, essentially every object you create will have its own API. The methods that are exposed are the API, and the objects have behavior and state which dictate what happens when the API is used. I have some experience with Objective-C, writing iOS apps. APIs are a huge part of creating anything in an object oriented language, and especially in iOS. Every object exposes an API that consumers utilize to get things done.
Most recently, I have been working at Cloud Elements where we deal with web based APIs, and more specifically, REST APIs. Our core product is built to expose a set of APIs that allow consumers to use the underlying service easily, and in a language agnostic way.
This is a high level look at what the Cloud Elements product does. It exposes a common API to each of its “hubs”. A hub is something like messaging services or payment services.In the example here, my super cool app, written in any language that can talk to a RESTful API, calls the common Messaging hub API. The hub then determines, based on current settings, which third party API to use to service the request.That determination can be made on things like which service is up or down; which service is least expensive, etc.
API Versioning: What happens when my API changes? How can I help clients deal with those changes, and what's really involved?API Documentation: Jeff didn't really mention this, but thought it fit well with the versioning aspect, and its usefulness overall.Different services, different architectures. What I mean by that is, the nature of APIs in general really lend themselves to a black box type of interaction between services. An API exposes an interface with a defined input and output, and what happens behind the curtains is largely unknown to us. It could be an Apache web server talking to a Tomcat app server, with Java and postgresql in the backend. It could be an email sent to someone who manually types in a response right? We just don't know, or really care, what the underlying architecture is of the API services we utilize, nor does it matter. So, I'll show a demo of the Cloud Elements product near the end that illustrates that point.
There are three main ways to accomplish API versioning. Content Negotiation, URI, and using a URI Parameter.
Content negotiation refers to the HTTP Header that indicates what the client is asking for from a content perspective. Who knows what an HTTP header is? Have you learned about that?HTTP Header: Message header of requests and responses in the Hypertext Transfer Protocol (HTTP). They define the operating parameters of an HTTP transaction. So, whenever you browse to a web page, these header values are set by the browser and shipped off to the server. You don't see them, normally, but they're there. Common fields in the header are things like Accept (Content-Types that are acceptable for the response; Accept: text/plain), Cookie (previously stored cookie), and Authorization (credentials).So, for example, the Cloud Elements API, which we'll see later, accepts json, and it returns json. That Accept header value tells the server what type of content the client is expecting.Who has heard of a MIME type? It's an identifier for file formats on the internet.
So let's say we have an API that lives at elements/messaging/search, that it's a POST request, and the input takes json with two properties, text and elementToken.
This is what the header might look like for that request.To use content negotiation for versioning, we would need to use a vendor MIME media type, which is essentially a MIME type specifically for our API. Here we have something like ce.messaging.sg+json, which is a type specific to our messaging, SendGrid API.The request is made initially as a POST request, with the input parameters (not listed) for a messaging search. The response we get back shows the content type that we requested, and it's just json data.
What if at some point we wanted to add a priority field to the json data? If the documentation for our specific MIME type says to ignore all unrecognized elements, then we can safely add it to the output, and existing clients should be fine with that.However, what happens if we want to change the recipients field to recipients-email? That's going to break existing clients, and we don't want to do that.
What we can do is create a new revision of the MIME media type that tells our application whether or not the recipient knows about this field change.If we see the ce.messaging.sg-v2+json Accept header value in our server code, we know exactly how to handle the request, and the resulting output.
Advantages:There is no versioning to clutter up the URI. There's always just one resource URI, and the versioning is determined by the header data.Disadvantage:- Some clients may not be able to access the HTTP header data easily, or at all. This is one reason, I believe, why many well known APIs (Netflix, Paypal, Drop Box) don't use this method. URI versioning is more widely compatible.
Next we'll discuss API versioning using the URI. This is where we place the version number of the API in the URI itself.
When I say URI versioning, I'm referring to putting the version number in the URI itself.When using URI for API versioning, it is recommended by some to point the permanent API resource to the latest API version. So, all of the URIs listed here would be aliases of each other, assuming version 2 was the latest API version.
If a client attempts to use an outdated version of the API, the request could be redirected to the permanent resource. The status code of the redirect can be used to indicate that the requested resource version is no longer supported. It is obviously up to you to determine how long to continue supporting each version, as you may want to support the last few, which is still fine.
So, using our previous example, the permanent URI resource would be pointing to the latest version, where priority is present, and the recipient property has changed to recipient-email.
The previous version would still return our original representation.
The previous version would still return our original representation.
The maintenance for the URI scheme will most likely involve hosting a new installation of the API application with each new revision. It may sound like a lot of work, but really if you install a new version, the old one will not be updated, so it can sit out there until you decide to stop supporting it. So, when do we stop supporting older versions? Typically, when a new minor version is released, the older versions will most probably need to stop being supported. This is because, with minor revisions, we've changed the structure of how clients interact with the API, so it makes sense that there would be back end changes we just can't continue supporting.
One of the advantages of URI based versioning is that it's very widely used. APIs like Tumblr, Groupon, and Drop Box, just to name a few, all use URI versioning with their APIs. Additionally, there's no need to rely on the client's ability to access HTTP header data when generating an API call.The disadvantage is that the URI now includes the version number, and it's possible that clients will be more difficult to maintain when switching between versions.
Next we'll discuss API versioning using the URI. This is where we place the version number of the API in the URI itself.
URI Parameter versioning is accomplished by sending a version query string parameter in with the API request. Just like the URI method, we can have the permanent URI, without a version parameter, just use the most recent version. Or, if a version parameter is sent in for a previous, supported, version of the API, we can route the request accordingly.Essentially everything I mentioned about the URI versioning method holds true for the URI Parameter method. There are several big name APIs that use this method (Netflix, Paypal).
That covers the primary methods of accomplishing API versioning.
So what do you choose? The answer is that it's completely up to you. There's no right or wrong answer to which method you choose, how long you support each version, or how you roll out new versions.A website that really helped me pull this together is from lexicalscope.com
The next topic I want to discuss is the actual documentation of your API once it's up and running. This is a very important part of the process, since without great documentation, nobody will know how to use your API, and nobody will actually want to use it.When putting together your documentation, you can think of these 4 main areas that you want to cover. Thanks to Programmable Web for this handy diagram.I'll show you a couple of nice tools that we use at Cloud Elements to provide developers as much help as possible in getting started with our APIs.
The last topic that I'll discuss relates to something Jeff mentioned in our conversation. Essentially, when thinking of APIs, we can think of them as the language of the internet. They're what glue services together throughout the web. One thing we notice is that, when we have an API to interact with, we most likely have no idea what's happening behind the scenes to make that API work. So, the implementation details of any given API are really unknown to us. Thought of another way, we can think of our own APIs. It doesn't really matter what technologies we use to make them work, as long as they fulfill the contract of the API.
Here's another look at what the Cloud Elements API is all about. We have hubs such as messaging and payment that provide a uniform API into the underlying services. In the case of the messaging hub, your super cool app makes an API call into the Cloud Elements API, and that call is routed to SendGrid, or Twilio, or MailChimp, or anything that we have an element for. What's great is that no matter what service you're using on the back end, be it SendGrid or Twilio, your super cool app does not have to change. It will still call the same Cloud Elements API.So, let's take a look at how that works. I'll show a quick demo of the Cloud Elements messaging API that we've sort of been using as examples all along. It's a pretty cool way to show that using a single API, we can access separate services that likely have very different implementations.What's the first thing you notice about the URI? It uses URI based versioning. In our case, it's actually in two places. One for the overall API, and one for the hub that we're using. If we were using content negotiation, we'd add a Header value in Postman with the necessary MIME type.