I was working on an university project with some course mates when I had this conversation. My course mate said:
“I don’t understand this design with APIs; why don’t we just make life easier for them and allow them to directly create objects in <framework in language X> and send them over the internet?”
Strangely enough, while our “Internet Systems” module introduced SOAP (a way to implement an API) and how to use it, many of my course mates did not understand the idea of what an API is or how it works. So over WhatsApp, I used this analogy to explain the basic concepts. I hope you’ll find this analogy useful.
(This analogy mostly applies to web APIs, though some concepts are applicable to other kinds of APIs as well.)
We Have A Bank
Imagine you’re running a bank.
You have a big, sturdy vault for storing money, and a logbook for recording how much money people have. A very easy (and lazy) way of running this bank is to grant open access to everybody. No checks are carried out, and the bank trusts people to do the right thing.
In our Open Access bank, for a customer to deposit money, they will have to:
- Go to the bank with the money in their hands;
- Open the vault and put the money inside;
- Go to the logbook and write “I am <name> and I deposited <amount> into the vault.”;
- Leave the bank.
There are two problems with this approach:
- The vault door is very hard to open, and requires physical strength. This is not very helpful for weaker people, and is possibly in violation of health and safety regulations. Similarly, people may not be able to read and write things on the logbook because of hand injuries or eye problems.
- In this model, we are trusting that people will be absolutely honest. However, as experience show, some humans are Terrible. Maybe somebody would come and deposit $100, but on the logbook they would write “I deposited $1000”. You can bet there will be that one person that comes in and takes everybody’s money, ruining our little money pooling cooperative.
Houston, we have a problem.
We Have A Bank Teller
What if we hire a person, who’s strong and smart, to deal with all those vault access operations? Enter Bank Teller Sally.
Let’s create a better bank: There’s now a wall separating the vaults and the logbook from the customers — it is no longer possible for a customer to directly interact with the vault. If they want to deposit or withdraw money, they’ll have to go through our friendly bank teller Sally.
In our new bank, for a customer to deposit money, they have to:
- Go to the bank with the money in their hands;
- Approach the bank teller Sally and say: “I am <name> and would like to deposit <amount> into my account.”;
- Sally takes the money, opens the vault and puts the money in. She is very strong and would be able to do this with no problem.
- Sally records this transaction on the log book.
- Sally goes back to the customer, and tells them that the money has been deposited.
- The customer leaves the bank.
Now nobody needs to open that bulky vault door anymore, and the accessibility office is pleased with the improvement.
We can now introduce the concept of APIs. API stands for “Application Programming Interface”, and according to Wikipedia (emphasis mine),
…[APIs are] a set of subroutine definitions, protocols, and tools for building application software. In general terms, it's a set of clearly defined methods of communication between various software components.
In plain English, APIs allows you to talk to other software easily. Why is this important?
In our analogy, the bank had a vault door that’s very hard to open. If we hire a bank teller and have them open the doors instead, then the customers won’t be required to open the vault doors. You will save customers’ time and make them happy. Happy customers, more business.
Similarly, if we abstract away the implementation details of operations (such as allocating system memory, activating the garage doors remotely, or launch rockets into space), it will help lower the programmers’ cognitive load (the amount of stuff a person has to remember at one time), therefore increasing productivity. For example, if we make an API that would launch rockets into space, a programmer could just use the API and in a blink of an eye, the engine would ignite, and the rocket will go straight up into the sky. Because the implementation detail is abstracted away (hidden behind an API), our programmer does not need to know rocket science to get a rocket into space.
With this abstraction of information comes another advantage: Components can be swapped out and replaced as long as they follow the same protocol (rules for communication). The bank doesn’t need to know how the customer got to the bank, and the customers don’t need to know the bank have moved all its money to a tax haven. As long as the bank teller’s still there and knows how to do their job (in this case, fetching money from a faraway place), the whole exchange will continue to work.
APIs are everywhere: From the simple
fork() in the OS to complex APIs such as Google Maps API, they’re all here to make a programmer’s life easier.
What’s In A Bank?
Let’s revisit our swanky new bank.
You might have noticed that there are two parts of the bank, and there are two areas: The front area, where customers queue up in an orderly fashion; and the back area, where the money handling happens. In the middle, we have the area where the front meets the back. Neither can cross the other side (save for a door for the bank tellers when they need to go home), and interactions can only happen in this area.
In API Terminology, we call this middle area the Interface; it is a place where software components interact. In our bank, the front area and the back area both aware that this exists, and agree to use this interface to exchange information.
Now, let’s assume Bob wants to withdraw money. Bob goes to the bank counter, and says: “Hi, I’m Bob, can I withdraw $500 from my account please?”
The bank teller says: “Yeah, sure, just a second.”
She knows very well how to withdraw money, so she does that. She comes back to the counter, and says: “Here’s your money. Thank you and goodbye!”
Bob then remembers his coursework about underwater basket weaving due next week. Feeling lazy and wanting to try his luck, he said: “Could you give me some information about underwater basket weaving?”
Sally, being a Bank Teller and not an underwater basket weaver, does not know what to say.
In API Terminology, a Protocol is a set of rules defining how components can interact with each other. Both parties must understand and uphold the same protocol for the communication to be successful. In this case, the bank teller understands withdrawing and depositing money, but she wouldn’t know how to go on Wikipedia and print the first result out for Bob.
This might not be very obvious, but notice that the language of this exchange was English. We call this a Format: it specifies how you can encode the data you want to send over to the other party. Their communication format here is English. As with protocols, both parties must understand and uphold the format; if Bob feels like showing off his Cantonese and goes「我想撳五百蚊出嚟呀唔該」, because Sally does not understand the Cantonese format, she is unable to do anything with Bob’s message, and the exchange fails. In the real world, common formats for web APIs include XML and JSON, though JSON is winning in popularity because it’s lighter and easier to read than XML, while XML continues to exist in the Java world and other enterprise settings (e.g. APIs that talk in SOAP). For applications that need to exchange a lot of data (especially multiplayer games), binary protocols like ProtoBuf and MsgPack are often used to save space and improve encoding/decoding efficiency.
Finally, let’s assume we want to expand our business into stock markets as well; we need a special kind of bank teller to deal with stock market trading. Let’s call this new stock trader Tom:
In API Terminology, an API Endpoint refers to a service provider that provides a specific subset of functions within the same Interface. In this case, Tom and Sally are both endpoints. Different endpoints can have different protocols and different formats.
To sum up: Interface is a place where different software components interact. A Protocol is a set of rules defining how they interact, and a Format defines how they talk to each other. Endpoints provide different functionalities within the same interface.
What Else Can Bank Tellers Do?
We’ve gone through all the API Lingo. Now let’s talk about some common features of APIs.
Let’s have Bob withdraw money again. This time, he tries to withdraw $10000.
We can instruct the bank teller to verify that Bob indeed has $10000 in his account before taking the money out from the vault (or else the bank would go bankrupt, silly). APIs can have verification logic built into it to ensure all operations are legal.
It turns out that Bob only has $100 in the bank. We can instruct the bank teller to tell him that he has insufficient funds in the account. APIs can have error reporting mechanisms to indicate an error has occurred, saving developers loads of head scratching when things go south.
Bob thinks that this is a mistake, and asks for the bank teller to give him a list of account he holds in the bank and how much money he has in each account. It turns out there are 200 of them. Going over them all at once isn’t very practical (Sally has to copy everything from the Logbook to show Bob), so she shows him 10 accounts at once. When Bob is finished with 10, he can then move on to the next 10. This is called pagination and paginating your datasets can save you bandwidth and server resources as you don’t need to fetch everything in the dataset at once. If Bob only wants to know a list of accounts with names starting with the letter A, he can ask Sally to only show him the relevant accounts. This is called filtering and it also helps save bandwidth and resources, as well as being easier to navigate.
After checking all the accounts, Bob now knows that he indeed doesn’t have $10000 in his account. Knowing that Alice bought stocks and earned tons of money, he leaves the bank, masquerades as Alice and re-enters the bank. He tells Sally: “I am Alice and I would like to withdraw $10000 from my account.”
We can instruct Sally to check for a valid ID and a bank card before she carries out the operation. In this case, Bob does not have either and leaves the bank, dejected. Authorisation and authentication can be built into an API to ensure only authorised personnel have access to specific data.
Finally, after failed attempts to get $10000 out from the bank, he goes into the bank and repeatedly withdraws $0.01 from his account (to spite Sally, probably). Because of company policy, Sally has to get $0.1 out from the vault every time, logs it into the Logbook, and gives Bob $0.1, which can be time-consuming. We can implement rate-limiting to control the use of server resources, to ensure users cannot abuse the service. In this case, the bank has imposed a 1-withdrawl-per-10-minutes rule; if Bob was to continue withdrawing $0.01 each time, he would be here for quite a while.
The API, combined with the features above, acts as a firewall to protect your resources from misuse while allowing legitimate requests through. Gone are the days where you can rob the bank and nobody would be able to stop you.
With Great Functionality Comes Great Responsibility
APIs are pretty sweet, however if badly designed, they can also frustrate your developers to no end. Here are some criteria that I think is useful when designing APIs:
- Make it clear what each endpoints do. While a Bank Teller tells you what the person does (sort of), titles like “Hyphenated-specialist” or “Professional Whistle Bending Expert” are not. Your endpoints should have basic names that is self-explanatory in purpose.
- Errors should be clear and human-readable. Telling a customer that they don’t have enough balance in the bank is useful. Telling a customer that error #506340 has occurred is not. Although it might be tempting to save a few hundred bytes of data by returning an error code, in reality they just make everybody’s life harder.
- Document everything. This is very important if you want your developers to not pull their hair out every time they encounter an error. Give them ample support with clear, concise documentation.
- Be consistent. The last thing you need when the deadline approaches is frantic Googling just because this API endpoint acts slightly different from the rest. Make sure your naming conventions, error handling and other behaviour are consistent across all endpoints.
- Keep your audience in mind. Think of how your developers will use your API, and make sure it is as easy and intuitive to use as possible.
And that sums up my take on APIs. Obviously this article grossly oversimplifies the diverse world that is APIs, but hopefully this has given you basic knowledge on how APIs work and how they can benefit your work.