The importance of client-side libraries for APIs

Michael Seifert, 2020-03-16, Updated 2020-10-01

Missing client-side components cost money

Imagine you are running a car rental business and have developed a backend service. The car rental services provides a REST-like API that can be used to book a car. The API is thoroughly documented on a website and a travel agency has found out about your services. They are integrating your car rental service into their Java-based system so that their customers can rent cars at their travel destination.

The API defines a communication protocol between two parties along with HTTP status codes and some JSON data types for requests and responses. The travel agency values clean design and therefore introduces a dedicated component in their system that integrates with your service. Suddenly, they are confronted with a bunch of new problems: They have to decide on a library to send HTTP requests, implement the data structures, and implement corresponding serializers and deserializers. They have to react to the different HTTP status codes in order to have proper error handling. Not to mention the testing effort to ensure the correctness of the library. Even for simple APIs, the risk of bugs in the implementation is pretty high, especially, if the car rental service provides no environment where customers can test the integration of their client library. [1]

It is not just the travel agency that has to solve this problem. Each of your customers has to implement that kind of component. The fact that your are not providing a client-side library is effectively increasing the maintenance cost of all your customers and makes integration with your product harder than necessary. If you are a software architect and you need to make a decision whether a specific software should be used or not, you need to factor in the cost for building, testing, and maintaining a component for accessing the software's API.

Characteristics of a good client library

It turns out that we can apply the same priciples as for any other software component. They should be…

… Ergonomic: A client library should be easy to use and hard to misuse. For example, it should not be possible for the user to create and send invalid data. A good client library should be unsurprising and make use of the conventions and best practices of the respective programming language. For example, it should use the native exception handling mechanism of the language and adhere to its naming conventions. [2]

… Coherent: A well designed client does not leak concepts of the underlying protocol to the users of the library. Our example service provides an HTTP API, so users of our client library should never have to deal with HTTP status codes, nor should they have to deal with the serialization mechanisms.

… Configurable: It is very important in a distributed system to be able to configure the number of retries per request as well as request timeouts. I have seen entire applications become unavailable, because of a failure to address this.

I created an API without a client-side component, what can I do?

At least you can provide an auto-generated client-library using a framework like OpenAPI.(opens new window) OpenAPI uses a YAML definition of the programming interface, in order to generate both a server-side stub and a client-side library. The resulting code lives in separate files and are highly coherent. Ergonomics of the generated code can be good or bad, depending on your target language. If you factor in the YAML API definition, which can get unwieldy very quickly, OpenAPI is not particularly ergonomic, though. Configurability of request timeouts and retry behaviour is hard as well.

In fact, most people that use REST-like APIs don't care about the ideas behind REST. They just want to have a way to perform remote procedure calls. For this purpose, there are dedicated frameworks that are better suited than REST-APIs. I recommend looking at gRPC.(opens new window) Except for a dedicated documentation endpoint on your webserver, gRPC comes with all the goodies of OpenAPI. In addition, it provides a more readable interface definition, a more efficient transport protocol, and does a better job at handling request timeouts. Support for retries of failed requests is in progress(opens new window) as well. If I was starting a new software project, I would pick gRPC over OpenAPI anytime.

If you need fine-grained control over what happens on the client-side, you still have the option to develop a client library from scratch. Sometimes, you may not even have a choice, because the API is not HTTP-based and the is no generator framework. The upside is that you have full control over all the criteria that make up a good client library.

  1. I am deeply convinced that the only effective way to test a client library are integration tests (i.e. making calls to the actual system and verify the outcome). People tend to disagreed, though. I suppose this is a topic for another article. ↩︎

  2. This is where most of the auto-generated client libraries fail in my opinion. ↩︎