API, for application programming interface, is one of those acronyms that is used everywhere from command-line tools to enterprise Java code to Ruby on Rails web apps. Unless you write every single line of code from scratch, you’re going to be interacting with external software components, each with its own API. Even if you do write something entirely from scratch, a well-designed software application will have internal APIs to help organize code and make components more reusable.
Diving a little deeper, an API is a specification of possible interactions with a software component. For example, if a car was a software component, its API would include information about the ability to accelerate, brake, and turn on the radio. It would also include information about how to accelerate: Put your foot on the gas pedal and push. The “what” and “how” information come together in the API definition, which is abstract and separate from the car itself.
One thing to keep in mind is that the name of some APIs is often used to refer to both the specification of the interactions and to the actual software component you interact with. The phrase “Twitter API,” for example, not only refers to the set of rules for programmatically interacting with Twitter, but is generally understood to mean the thing you interact with, as in “We’re doing analysis on the tweets we got from the Twitter API.”
Let’s dig in by looking at the Java API and the Twitter API as examples. First, we’ll get a quick picture of these two APIs and how they fulfill the definition of “what” and “how.” Then, we’ll talk about when you’ll likely use APIs and what goes into a well-designed API.
The Java API
The Java API is a library of software components available “out of the box” to anyone who has installed the Java Development Kit. These components implement common tasks and generally increase productivity because programmers don’t have to start from scratch every time. One of the basic components used in software is something called a List, which, as you might expect, keeps track of a list of items. The Java API defines what you can do with a List: add items, sort the list, determine if an item is in the list, etc. It also specifies how to perform those actions. In order to sort the List, you need to specify how you want the List sorted: alphabetically, numerically descending, brightest to dullest color, etc.
The Twitter API
The Twitter API is a web-based JSON API that allows developers to programmatically interact with Twitter data. Unlike the Java API, which is included in the Java Development Kit, the Twitter API is a web-based API. It must be accessed by making requests over the Internet to services that Twitter hosts.
With a web-based API such as Twitter’s, your application sends an HTTP request, just like a web browser does. But instead of the response being delivered as a webpage, for human understanding, it’s returned in a format that applications can easily parse. Various formats exist for this purpose, and Twitter uses a popular and easy-to-use format called JSON. (If you’re not familiar with JSON, you might want to spend a few minutes reading up on it here.)
One of the basic elements in Twitter is a tweet. The Twitter API tells you what you can do with tweets: search for tweets, create a tweet, favorite a tweet. It also tells you how to perform these actions. To search for tweets, you need to specify your search criteria: terms or hashtags to look for, geolocation, language, etc.
The Twitter API, along with many other web-based APIs, is an example of a REST API, which is to say that it is an API that uses the architectural style of Representational State Transfer (REST). REST, formally introduced by Roy Fielding in his doctoral dissertation in 2000, is a set of architectural components, design principles, and interactions used for building distributed systems that involve media of any kind (text, video, etc.). At its core, REST is a style of building systems that allows for flexible communication and display of information across the web while providing structure necessary to easily build general purpose components.
In a REST API, a resource could be pretty much anything, but examples include a user, a list of tweets, and the current results of a search for tweets. Each of these resources is addressable at a resource identifier, which in the case of web-based REST APIs is usually a URL, such as https://api.twitter.com/1.1/users/show?screen_name=twitterdev. When an application requests a resource using the identifier, the API delivers the current representation of that resource to the application in a format that the application can consume, such as a JPEG image, HTML page, or JSON.
One of the big differentiators of REST is that it involves sending data to the requesting application. While this provides great flexibility, allowing the application to do whatever it wants with the data, it comes at the cost of efficiency. Sending data over the web for processing is quite slow compared to doing the processing where the data resides and then sending the results. Of course, the problem with the “efficient” approach is that systems hosting the data would need to know what applications want to do with it ahead of time. Thus in order to build an API that has general purpose usability and flexibility, REST is the way to go.
API as abstraction layer
When it comes to software, APIs are literally everywhere. APIs go hand in hand with one of the most fundamental concepts in computer science: abstraction. Abstraction is just a way of organizing the complexity of a system so that complicated actions can be handled in a simple way. Think of this abstraction like those Amazon Dash Buttons, the battery operated, push-button circuit boards you can use to order staples from Amazon. This is what they look like:
You order a Dash Button from Amazon and use an app on your smartphone to associate it with your Wi-Fi network, your Amazon account, and a product, say, your favorite brand of paper towels. Then, whenever you want to order more paper towels, you just press the button. The Dash Button connects to the Internet and sends a message to place an order on your account. A few days later, paper towels arrive at your doorstep.
Like an API, the Dash Button is a blissfully simple interface that hides all kinds of complexity behind the scenes. The ID of the product you ordered must be retrieved from some database. Your delivery address must be pulled from your account. The nearest fulfillment center stocking your paper towels must be determined, then notified to remove an item from the available stock and package it up. Finally, the package must be routed through some combination of airplanes, trucks, and vans along with other packages in a way that ensures that all the packages will reach their destinations efficiently.
Now imagine you had to coordinate all of these things as a customer. You’d never order paper towels because it’s too complicated and time consuming and you have better things to do. Luckily, the whole ordeal is abstracted away from you. There is a long, interconnected chain of computer systems and human processes that make those paper towels show up at your doorstep, but all you have to think about is pressing a button. This is what APIs are like for programmers. They take an overwhelming amount of complexity and define a relatively simple set of interactions that you can utilize instead of doing it all yourself. In any software project, you’re likely using tens if not hundreds of APIs directly, and each of those APIs relies on other APIs and so on.
API design is the process by which the “what” and the “how” of an API are formulated. As with anything else that can be created, varying levels of thought and care are put into API design, resulting in varying levels of API quality. Well-designed APIs have consistent behavior, take their context into account, and keep the needs of their users in mind.
Consistent behavior within an API greatly impacts the speed at which it can be learned and the likelihood of programmers making mistakes when using it. Generally, APIs that perform similar actions should behave similarly, regardless of their technical differences. For an example of an inconsistent API, let’s look at the two ways to add an item to a List in Java:
Even though the two methods of adding items to a list do the same thing, their return types (boolean and void) are different. Developers using this API now have to keep track of which method returns which type, making the API harder to learn and its usage more error prone. It also means the code that uses these methods becomes less flexible, because it has to change if you want to switch the way you’re adding elements.
Taking context into account is another form of consistency, although it has to do with factors external to the API. A great, non-software example of this is how the rule of the road—right hand traffic or left hand traffic—influences car designs for different countries. Car designers take that environmental factor into account when locating the driver seat on the right side or left side of the car.
In API design, taking context into account usually means that you’re adhering to commonly accepted best practices and taking inspiration from other APIs that your users will likely be familiar with. Say you’re building a library that provided a new kind of List to a Java application, maybe one that was designed to work specifically with very large lists. The API of that List should probably include an add method that behaves in the same way the Java List add method works. That way, users can easily adopt your library because they already know how to use it.
Knowing your users and keeping their needs in mind is of the utmost importance in API design. Your API will have happy users if you understand their pain points and help them avoid that pain. For the same reason, you might choose to break with other rules of good API design. If you were writing a web API, the de-facto standard today is to use JSON as the interchange format. However, if your API will be serving scientific users who will be retrieving massive amounts of data, JSON is going to be too verbose and cumbersome to serve them well. As a result, you may choose to use a binary format like GRIB, even though it’s an extremely uncommon choice in the general sense.
APIs are an essential component of software design and they exist at every level of the software stack. They provide a way to define and manage abstractions by telling us what we can do with software components and how we can do it. Well-designed APIs support efficient, fluid, and effortless adoption and use, while poorly designed APIs tend to cause headaches every time they’re used. Do you have any more questions about APIs? Please continue the conversation with me on Twitter @freethejazz.