Python API clients with Tapioca

In this post I'll present to you Tapioca, a Python library to create powerful API clients with very few lines of code. If you don't want to read through the reasons why I've built it, you may just jump straight to the Tapioca Wrapper section.

Why do we need a better way to build API clients

Integrating with external services is painful. Here at Vinta, we build and deal with both public and private APIs on the daily basis. Having worked in many of those projects I can safely tell that we are currently in hell when it comes to integrations. There are two ends in this mess: one is the result of poorly designed APIs and the other is the lack of standards and good practices for building API clients.

It begins with API design. As we get away from RPC based architectures and move to more REST style  systems, there is clearly a lack of well formed practical set of rules or at least a broad misunderstanding of the rules for building APIs. This is actually not a surprise since we were used to RPC and its well defined protocols while REST provides a set of guides, and is actually an architectural style. Luckily there are people trying to solve this problem, the json:api project is a good example of where we should aim for good design and standardization.

Roy Fielding, creator of the REST architectural style

On the other side there are people trying to use these poorly designed APIs. Most developers doing integrations don't want to deal with the complicated and unique patterns API creators freely chose for their systems. The easiest [and most common] way of trying to stay away from this mess is to use open source available API clients (or API wrappers). Which sounds like a good plan as long as you are doing a simple integration with a single service. As you move to multiple complex integrations you start noticing that the API client spectrum is as messy as the API services. Every single wrapper lib has it own unique way of dealing with authentication, pagination, versioning, throttling and parameter passing. Not to mention the huge amount of duplicated code to perform the exact same set of features among them.

While we developers using public APIs do not have control over how they are built, we do have on the API client side. This takes us to Tapioca.

Tapioca Wrapper

Tapioca is a Python API client maker. It gathers most of the features API clients implement and puts them in an extensible core. Wrappers will then extend this core implementing only the specifics from each service (such as authentication and pagination) and get all the common API client features for free. Tapioca approach also comes in handy because regardless of the service, clients look the same in the way you interact with them. Once you've worked with a Tapioca lib you know how to use them all, no need to learn things from scratch.

Here is the tapioca-facebook in action.

>>> from tapioca_facebook import Facebook
>>> api = Facebook(access_token='{your-access-token}')
>>> feed = api.user_feed(id='me').get()
>>> print([0].link)
<TapiocaClient object

And now the tapioca-twitter:

>>> from tapioca_twitter import Twitter
>>> api = Twitter(
>>>    api_key='{your-api-id}',
>>>    api_secret='{your-api-secret}',
>>>    access_token='{your-access-token}',
>>>    access_token_secret='{your-access-token-secret}')
>>> statuses  = api.statuses_user_timeline().get()
>>> print(statuses[0].text)
<TapiocaClient object
('RT @vintasoftware: Our latest blog post was featured in @thedjangoweekly and '
 '@importpython newsletters! Go check it out:')>

Pagination is also very easy and similar for both services.


>>> feed = api.user_feed(id='me').get()
>>> for item in feed().pages():
>>>    print(


>>> statuses  = api.statuses_user_timeline().get()
>>> for item in statuses().pages():
>>>    print(

There are many other features (e.g.: serialization) you can check here.

To give you an idea on how easy it is to build a client with Tapioca, here is the source code for the tapioca-facebook we just played with. See the code in the repository.

from tapioca import (
    TapiocaAdapter, generate_wrapper_from_adapter, JSONAdapterMixin)
from requests_oauthlib import OAuth2

from .resource_mapping import RESOURCE_MAPPING

class FacebookClientAdapter(JSONAdapterMixin, TapiocaAdapter):
    api_root = ''
    resource_mapping = RESOURCE_MAPPING

    def get_request_kwargs(self, api_params, *args, **kwargs):
        params = super(FacebookClientAdapter, self).get_request_kwargs(
            api_params, *args, **kwargs)

        params['auth'] = OAuth2(
            api_params.get('client_id'), token={
            'access_token': api_params.get('access_token'),
            'token_type': 'Bearer'})

        return params

    def get_iterator_list(self, response_data):
        return response_data['data']

    def get_iterator_next_request_kwargs(self,
            iterator_request_kwargs, response_data, response):
        paging = response_data.get('paging')
        if not paging:
        url = paging.get('next')

        if url:
            return {'url': url}

Facebook = generate_wrapper_from_adapter(FacebookClientAdapter)

That's right, it's a entire client lib from a 37 line file plus the [ridiculously simple] resource mapping.

You can benefit from the flavours that were already developed. Or you can create a new Tapioca for a public API or your private service using the Cookiecutter template.


Want read more about APIs? Check out these posts from our blog:

Filipe Ximenes

Founder & Chief Technology Officer