In this post we’ll talk about how to (and how not to) design internal APIs so they are reusable. By “Internal APIs” I mean the ones used only from inside your company, by other products or components that your company has control over.

At the end of this post you’ll have a good grasp of some of the pitfalls when designing reusable APIs.

I’ve seen many APIs designed for one particular client in mind. While this is not really a bad thing in itself, building the client-specific API before we have built a more generic RESTful API is not the optimal solution.

So, let’s look at an example. Let’s imagine that we have been tasked with developing a movie database web application. We decide to split the application into two parts: a frontend application written in AngularJS and an API which will provide the data.

The Requirements

After spec’ing out the AngularJS client we know that the client will need the following info:

  • The 10 newest movies
  • The 10 most popular movies
  • A movie search functionality which can filter by movie title and year
  • All the details for each movie

Knowing this, we sit down to design our API. The easiest option is to implement four endpoints, one for each of the functionalities above. Simple and quick, this will get the job done. Let’s look at an example url to search the movies by title:

GET http://www.example.com/api/movies/search?title=lost

Here we want to get a list of all the videos which have “lost” in the description. The API might return a JSON like this:

{
  "movies": [
    {
      "movie_id": 1327,
      "title": "Lost",
      "year": "2004",
    },
    {
      "movie_id": 3286,
      "title": "Lost",
      "year": "1983",
    },
    {
      "movie_id": 4405,
      "title": "The Lost City Of Z",
      "year": "2016",
    },
    {
      "movie_id": 4892,
      "title": "Lost In Translation",
      "year": "2003",
    },
    {
      "movie_id": 4964,
      "title": "Lost In Space",
      "year": "1998",
    }
  ],
  "total_count": 8,
  "page": 1,
  "pages": 2,
  "results_per_page": 5
}

This information is great, here we have only the movie information that we need in the search results page and the list is paginated so we have the count readily available. So what’s wrong?

The problem is that this API call is not based on the smallest building blocks of the application. In this case the smallest building blocks would be a “movie”. In the response we have some information relating to each movie but it is incomplete. Although this information is exactly what the client needs to display the search results, this API call is not reusable if another client needs different movie information.

Is there a better way? Before we look at it let’s quickly have a look at the Single Responsibilty Principle.

The Single Responsibility Principle (SRP)

single responsibility principle

This principle is well known among most programmers, it says that an object or a class should only do one thing, or to put it another way, an object should have only one reason to change. Why? Because it makes things more component-like and reusable and it separates concerns. By dividing our code into the smallest possible building blocks (things that only do one thing) those small building blocks become much more reusable. Consider a class that does too many things at once. Run your tests, do a quick manual test of your application and it will work. But is that big class reusable? Not really, because if I want to use a small piece of functionality of the big class I need to drag along the entire class. But lets imaging that I do this anyway, since I don’t want to duplicate code when it is already written in the big class. Because I have now coupled the new code to the big class, so if something changes in that big class then it is possible that we break something in another part of the application even if the change didn’t have anything to do with the functionality that I am using from the big class!

The solution, and what the SRP tries to encourage, is to break things down into the smallest building blocks possible. Lets go back to the moment when we are deciding whether or not to reuse the code from the big class or duplicate the code. Our choices are to depend on and use the big class anyway even though we don’t need all the functionality or we could duplicate code, which is another Bad Idea™. But we have another option. We can refactor the big class to separate out the code which we need to use; we will be splitting the big class down into “smaller building blocks” if you like. After having done this it will be much easier to reuse the smaller building blocks from other parts of the code too.

You’ll find a great explanation of the Single Responsibility Principle (and the Open-Closed Principle) here.

Applying the SRP to an API: RESTful and generic

So how does the SRP apply to the design of APIs? Instead of building an API that is built especially for this one client we will try to build a generic RESTful API which returns the smallest building blocks possible for the application. You might know these small building blocks as Entities or Resources. Whatever the terminology, the idea is that we will build a RESTful API that will work with entire resources, even if our current client doesnt need all the info right now.

Instead, let’s make our search endpoint return only the movie ids instead of the incomplete movie information:

GET http://www.example.com/api/movies/search?title=lost

This might return:

{
  "movie_ids": [1327,3286,4405,4892,4964],
  "total_count": 8,
  "page": 1,
  "pages": 2,
  "results_per_page": 5
}

Notice that now we have removed the movie information. We can get the movie details with another API call using the movie id. That call might look like this:

GET http://www.example.com/api/movie/1327

This endpoint would return the full movie entity, for example:

{
  "movie_id": 1327,
  "title": "Lost",
  "year": "2004",
  "description": "Jeremy Stanton (Cain), an ordinary man, makes an extraordinary mistake.",
  "genres": [
    "action",
    "adventure",
    "thriller"
  ],
  ...
}

This way we have to make more API calls because the API is more fine-grained, we cannot customize the API to return more information just because it suits the client. However this problem is usually completely mitigated by caching since RESTful APIs are very easily cached. In this example the movie details are perfectly cacheable, the key point is that they will be cached not only for this specific client but also across any other clients who use the same API.

Comparing the alternatives

So, by forcing the client to use a true RESTful API instead of customizing the API for the client we gained a few things and we lost a few things:

Pro’s

  • The API is much more reusable. We can consume this API from other clients or even other APIs since it is generic
  • Resources can be cached (server side) even across different clients

Con’s

  • The client is forced to have more logic since they might not be able to get all the info they need in one single API call anymore.
  • Because of the need for more API calls, performance of the client might decrease. This is usually mitigated by caching but if it is still a problem then building another API which consumes the generic one might be a solution.

So, let’s say you are talking internally with all the team members about the design of the API. The team in charge of making the AngularJS client understandably want performance and ease of use so they want the “custom” API. However, it’s important to realize the impact that this will have: if you decide to build the generic RESTful API then you will have a more reusable building block for other services (even APIs!). If performance of the AngularJS client is a mega priority then there will be nothing holding you back from building another custom API that consumes the generic one! This way you get the best of both worlds, but it’s important to realize that having a generic RESTful API is a huge advantage so building it before a “client-specific API” is usually a better idea.

So, if you find yourself needing to design an API try to keep it as generic as possible. If the client requires special endpoints, check if building another API which consumes the generic API and transforms/merges the results into what the client needs would solve the problem.

Have you designed an API recently? Leave a comment below with how you did it.