Almost every developer worth his or her salt finds themselves in need to write an API at some point in their life. Whether it’s a web endpoint API or a language level API, the design is critical to its success. But what makes a good API? I suppose everyone has differing opinions on this, but I figured I put my two cents out there and maybe help one or two people find their footing in this vast world of programming. I’m not saying this is the best or correct way – this is merely my opinion! If anything written here seems off, please leave a comment to help me learn as well! That is core to our industry, and so I’m doing my best to pay back to the community.

An API to those unfamiliar, stands for Application Programming Interface. It is the methods/functions that expose the functionality of one program, to its consumption in another. If a user interface is how a person interacts with a program, an API is how a program interacts with another program. There’s probably an decent API between Agent Smith and the machine mainframe (haha).

The first thing to note here is who your users are. Your users are not your average, regular online explorers. Developers are your users, and developers come from a wide background of experiences that make each of them unique. That means that each developer is going to look at your API in a slightly different way. As such, each of them is going to learn your API through a different perspective. Luckily, if one has spent enough time in the world of programming, some patterns do emerge. These patterns enable design principles and ideas that we can leverage to make our API’s easier/quicker to use.

Your first goal as an API designer is to make it as intuitive and as easy to use as possible. Your second goal is to leverage that intuitiveness, along with its functionality to save developers time in whatever tasks your code may simplify. I bolded that last statement due to its utmost importance. So, let’s get started!

Introducing Developers to your API

Our world is vast. We live in a cosmic sea of code that is ever expanding. Perhaps one day, there will be a ‘Hubble’ constant to calculate the expansion of the worlds codebase (I wonder if it’s expanding faster or slower?). But for now, it’s very easy to feel lost. Having great introduction pages or tutorials to your API is paramount if you want to gain traction in our world.

I say this as a lone wanderer who has used many API’s. Of the great one’s I have come across, this seems to be a common point. Take a look at jQuery‘s website if you want a solid example of simple and clear introductions. If I can’t figure out what your API does within 2 minutes of looking at your websites homepage (or video, etc…), I am very unlikely to explore it further, let alone use it. I mean, what am I exploring? It seems like a big waste of time, and sometimes it turns out to be. You may have an idea of what something does, only to find out your idea was a mere fabrication based on your brain making connections to past experiences. Similar has no relation to being equally identical. Create a storefront to your API and make its purpose clear.

Naming Your Methods

You want an API that fits well into other applications. Think of two puzzle pieces fitting together. That means that your methods should be clear, concise and well named. The naming of your methods could even be argued to be the most important component of what makes a good API, great. They have to be bite sized, yet descriptive. They have to be named appropriately (this is important, we’ll talk about this in a little bit), and they have to follow some type of already understood pattern. Essentially, you almost want your API to be self documenting. Good code explains itself and also behaves in a predictable manner – the same goes for API’s.

Patterns reduce learning curves. If someone is familiar with another concept from the past that applies to something new that they are learning, we can assume they’ll learn this new thing at a much greater pace. Not only that, they’ll be able to make a reasonable ‘guess’ when they want to do something they’re unsure of.

Let’s look at some examples from Python. Let’s assume you want to get the length of a string. We get the length as follows:

len("string")
>> 6

How about an array? Well, if you guessed we use the len() method, you’d be correct!

len([1,2,3,4,5,6]) 
>> 6

Consistency allows developers to make reasonable guesses when they are faced with the unknown. This can reduce the lookup time, and thus save the developer time. Isn’t that the whole point of an API to begin with? You’ll hear this whole ‘time saving’ thing over and over again in this article.

Let’s take naming a bit further. If a method call deletes an item, well then you should name it:

item.delete()

If a method call deletes an item asynchronously (that is, without blocking the main thread), name it something like:

item.deleteAsync()

If you have other methods that have synchronous and asynchronous versions, use the same exactly convention you’ve used in the past:

item.update()
item.updateAsync()

In essence, you want a developer to be able to learn your API as fast as possible, in a way that makes the most amount of intuitive sense. It’s worth repeating – your goal with an API is to save developers time. You’re offering developers a toolbox. You want to make sure that those familiar with common tools, such as the programming equivalent of a hammer, drill or a saw – will already be familiar with your tools. A skilled craftsman doesn’t have to learn how to use a multi-socked screw driver if he or she has already has several regular screwdrivers. He or she bought it so that all of the different types of heads can be utilized at a more rapid pace. However, it still operates as a screwdriver. Keep things consistent. This reduces what’s called ‘ramp up’ time, which is how long it takes for an uninitiated person to get initiated with your API.

Another tip I heard but have yet to use is to name dangerous methods something rather ugly. For example, if one of your methods causes the server to crash intermittently, you may want to call it:

serverRandomCrash()

I know, you’re laughing. But when you really think about it, it does make sense. I’m sure every developer out there is slightly afraid to type DROP into an SQL statement. That’s because dropping something is scary. Things break when they’re dropped, and so, the word carries with it a sense of danger. Strike fear in the hearts of developers when you really need to, otherwise they may just end up in a panic. A little fear is okay – but panic after an unexpected negative outcome is terrifying.

Web Endpoint API’s

I just wanted to make a slight mention about writing web endpoint API’s. Your goal when writing endpoints is to expose your resources and any computation that may want to be done to them, in a way that is easy to consume and understand.

Let’s look at a small example. We’ll assume we have a Users resource that contains standard user information.

Users

email – String
password – String
firstName – String
lastName – String
country – String
created – DateTime

You would expect the URL to this resource to begin with /users. The calls may look something like this (you shouldn’t ever have to put emails in the URL, this is just an example):

Get All

GET: http://www.example.com/api/users

Get By Email

GET: http://www.example.com/api/users?email=neo@email.com

Create

POST: www.example.com/api/users

Request Body:

{
    "email" : "neo@email.com",
    "password" : "Matrix123!",
    "firstName" : "Mr",
    "lastName" : "Anderson",
    "country" : "Canada"
}

Get Users Full Name

GET: http://www.example.com/api/users/fullname?email=neo@email.com

This could return:

{
    "fullName" : "Mr Anderson"
}

We don’t want to expose how things are done, we just want to expose the results. This also comes back to saving the developer time. Instead of writing a method to concatenate the first and last name with a space in the middle, your API may want to do that them if your foresee it as common functionality.

Authenticated Requests

Depending on your authentication scheme, this may vary. Let’s assume you’re using token authentication. You would make your requests as normal, however your header would contain an Authorization value that contains a Bearer token. This is an example of such a header that uses token authentication to fetch all users:

GET /users
Authorization: Bearer (token value)
Accept: application/json

The application will authorize the request based on the validity of the Bearer token value.

Overview

Categorize your API by the resources you’d like to expose. Think about how users will use your API, and save them time by doing common functionality for them. One may also assume that as a developer, seeing a well named API call in code is almost self documenting. Getting the full name of the user implicitly implies the first and last name will be concatenated. You may be able to imagine much more complicated functionality, such as parsing an image using machine learning algorithms.

Imagine the difference between a call to http://www.example.com/images/contains-animals rather than writing your own ML algorithm to do the same thing. You just saved massive amounts of time, and your call to /images/contains-animals tells every programmer almost immediately what you did to the image (in this case, you checked to see if the image contained any animals).

Documentation

I wanted to close this with a small comment on documentation.

No one is born knowing how to use React.js, along with every other programming language or library that they have spawned. There must therefore, be some resource that exists to inform us on how to use each of these tools. Documentation is the bible when it comes to a point of truth for your language, library or API. It is where developers will look when they want to figure out what something does or how to properly make calls to certain methods.

Your API’s documentation needs to be extensive, clean, informative, complete and correct. It doesn’t matter if its boring to look at, you’re not expecting people to read it cover to cover. However, it must contain all information pertaining your API that a developer may want to know.

What parameters do certain methods require? What do these methods return? Why does this method behave oddly sometimes? Why does a method that fits into a common pattern not produce the results one expects? Your documentation needs to contain all of this information, as one would expect a reasonable developer to be search for answers to all of these questions.

Let me give you an example from Google where the documentation has failed me.

I was working in Google Cloud Endpoints and required user information. If you look at the documentation, you simply have to call:

endpoints.get_current_user()

It looks clean, and in fact, this returns a user object. However, Google’s own documentation tells developers to NOT store this user object, even though the datastore contains a UserProperty for that very purpose.

Instead, they tell you that you should store the user ID. The reason for this is that the user object can change if the email tied to the account is ever changed. However, the user ID always persists. That makes perfect sense, so let’s store the user ID instead.

So, you, as the developer, attempt to get the user ID as per the documentation. You make the call:

endpoints.get_current_user().user_id()

This time however, the result is None.

Why did it return None? I expected it to return a user ID. I mean, Google’s own documentation here is telling that this line of code should work. After mauling this over and exploring Stackoverflow, you find a trick that works. The trick is to save the user object to the Datastore’s UserProperty, and then retrieve that new entity. Once you have that user object, you can make the same call ‘user_id()’ to now produce the value you’re looking for. But I thought we weren’t suppose to save user objects? In fact, if you’re using NDB (as opposed to the other DB version of the Datastore), this trick won’t work. This is weird, so you dig further.

After many hours of pulling your hair out, you find this response to your problem from a Google developer:

https://code.google.com/p/googleappengine/issues/detail?id=8848#c47

“Fixing this issue is not on our roadmap — the Google ID token contains a G+ userid, not an App Engine userid, so the App Engine user object supplied cannot contain the App Engine userid. We recommend you use one of the workarounds mentioned above.”

That means that not only does the functionality of the API not match the documentation, it is a KNOWN issue and is not being fixed. Furthermore, the documentation has not be updated! I mean, users and the ID value seems to be a pretty critical component to any application that uses Cloud Endpoints, right? This should be the plague to any API designers and must be avoided at all costs. Your goal was to SAVE time, not consume more of it.

 

I want my coffee money back!

 

Closing Statements

 

I don’t mean to single Google out, it was just the most recent example I could think of.  In fact, I love working in the Google stack. I also just want to say that I am not an expert on API’s by any means. I have however, learned a thing or two on what makes good API’s vs what makes bad API’s through using and writing them.

 

I hope this information helps a few people out there! If you have any feedback or think something should be changed/added, reach out! I love learning, and would never turn down the chance to better myself.

 

Cheers and have fun programming!
Advertisements