Building a wrapper¶
Wrapping an API with Tapioca¶
The easiest way to wrap an API using tapioca is starting from the cookiecutter template.
To use it, install cookiecutter in your machine:
pip install cookiecutter
and then use it to download the template and run the config steps:
After this process, it’s possible that you have a ready to go wrapper. But in most cases, you will need to customize stuff. Read through this document to understand what methods are available and how your wrapper can make the most of tapioca. Also, you might want to take a look in the source code of other wrappers to get more ideas.
Tapioca features are mainly implemented in the
TapiocaClientExecutor classes. Those are generic classes common to all wrappers and cannot be customized to specific services. All the code specific to the API wrapper you are creating goes in your adapter class, which should inherit from
TapiocaAdapter and implement specific behaviours to the service you are working with.
Take a look in the generated code from the cookiecutter or in the tapioca-facebook adapter to get a little familiar with it before you continue. Note that at the end of the module you will need to perform the transformation of your adapter into a client:
Facebook = generate_wrapper_from_adapter(FacebookClientAdapter)
Plase refer to the TapiocaAdapter class document for more information on the available methods.
Here is some information you should know when building your wrapper. You may choose to or not to support features marked with (optional).
The resource mapping is a very simple dictionary which will tell your tapioca client about the available endpoints and how to call them. There’s an example in your cookiecutter generated project. You can also take a look at tapioca-facebook’s resource mapping.
Tapioca uses requests to perform HTTP requests. This is important to know because you will be using the method
get_request_kwargs to set authentication details and return a dictionary that will be passed directly to the request method.
Use the methods
response_to_native to correctly treat data leaving and being received in your wrapper.
TODO: add examples
You might want to use one of the following mixins to help you with data format handling in your wrapper:
process_response method to identify API server and client errors raising the correct exception accordingly. Please refer to the exceptions for more information about exceptions.
TODO: add examples
get_iterator_next_request_kwargs are the two methods you will need to implement for the executor
pages() method to work.
TODO: add examples
serializer_class attribute or overwrite the
get_serializer() method in your wrapper for it to have a default serializer.
from tapioca import TapiocaAdapter from tapioca.serializers import SimpleSerializer class MyAPISerializer(SimpleSerializer): def serialize_datetime(self, data): return data.isoformat() class MyAPIAdapter(TapiocaAdapter): serializer_class = MyAPISerializer ...
In the example, every time a
datetime is passed to the parameters of an HTTP method, it will be converted to an ISO formatted
It’s important that you let people know you are providing a serializer, so make sure you have it documented in your README.
## Serialization - datetime - Decimal ## Deserialization - datetime - Decimal
Please refer to the serializers for more information about serializers.
Refreshing Authentication (optional)¶
You can implement the
`is_authentication_expired` methods in your Tapioca Client to refresh your authentication token every time it expires.
`is_authentication_expired` receives an error object from the request method (it contains the server response and HTTP Status code). You can use it to decide if a request failed because of the token. This method should return
`True` if the authentication is expired or
`False` otherwise (default behavior).
api_params and should perform the token refresh protocol. If it is successfull it should return a truthy value (the original request will then be automatically tried). If the token refresh fails, it should return a falsy value (and the the original request wont be retried).
Once these methods are implemented, the client can be instantiated with
`refresh_token_by_default=True` (or pass
`refresh_token=True` in HTTP calls) and
`refresh_authentication` will be called automatically.
def is_authentication_expired(self, exception, *args, **kwargs): .... def refresh_authentication(self, api_params, *args, **kwargs): ...
XMLAdapterMixin Configuration (only if required)¶
Additionally, the XMLAdapterMixin accepts configuration keyword arguments to be passed to the xmltodict library during parsing and unparsing by prefixing the xmltodict keyword with
xmltodict_unparse respectively. These parameters should be configured so that the end-user has a consistent experience across multiple Tapioca wrappers irrespective of various API requirements from wrapper to wrapper.
Users should be able to construct dictionaries as defined by the xmltodict library, and responses should be returned in the canonical format.
Example XMLAdapterMixin configuration keywords:
class MyXMLClientAdapter(XMLAdapterMixin, TapiocaAdapter): ... def get_request_kwargs(self, api_params, *args, **kwargs): ... # omits XML declaration when constructing requests from dictionary kwargs['xmltodict_unparse__full_document'] = False ...