Design of a wrapper for external API

Lev Rubel
4 min readMar 26, 2015

--

How many times you needed to integrate some external service to your app via API that has no library for Python? Making one call might be easy, but what if you need to use almost every endpoint in that API?

Authentication process

In this article we’re going to explore excellent API of receiptful.com. They provide one of the most straight-forward looking API in their niche. And the best part: it’s completely free to use.

First things first, we need to read documentation of the API service we’re going to use. In the “Authentication” section lies information about how their servers are going to detect us as we send requests to their server:

All paths should prefixed with https://app.receiptful.com/api/v1 and will need the following HTTP header:
X-ApiKey: YOUR_API_KEY
Your API Key can be found on the profile page in your Receiptful control panel

So, we need to obtain the API key for us to send requests. Luckily, there’s not much you need to do to get one. Just sign up and at the last step of registration process you’ll be able to copy that precious key to your clipboard.

Different services use different kinds of authentication process, so make sure you check out how exactly you should use desired API. Other popular choices besides Header Token Auth are: OAuth, JWT, HTTP Basic Auth.

Structure is the key

You would like to consume the API the most simple and convenient way possible, so when you design a wrapper always aim for the usability for the end users (even if the only user of your library is you).

We want to use any API library (the one we build here as well) as if we were talking commands to external service. So the perfect end usage of our library should look similar to this:

And if we need to pass some parameters to GET, POST or PUT requests, we should be able to take advantage of our consistent interface of functions&

Now, lets take a look at the list of methods in Receiptful API. There are 13 endpoints and some of them receive GET and POST, while others require PUT and DELETE. So it is natural to build helper methods upon unified interfaces for sending requests with specific HTTP methods to the API.

Building blocks

Our main class should contain a couple of crucial parameters that will be used in almost every method. These are: request session, api_key and base_url. And what should we do when we need some data in every instance of the class? We set them in the __init__.

We’re going to use amazing requests library for making HTTP requests. For the sake of DRY, when you planning on making a lot of requests with similar parameters (cookies, headers, etc), use requests sessions. Basically, sessions can be used to provide default data to the request methods.

Note, how we put API_VERSION in its own constant instead of hardcoding it into url. This allows us to easily show developers what api version this library is for. Also, if you decide to write library for version 2 of API, you can easily do so by subclassing Receiptful, replacing API_VERSION and necessary methods.

Last building blocks we need to add are helper methods for making actual requests to the API.

The convenience of these methods is in concatenation of base API url and specific endpoints via “url” argument.

The only key difference between them is that some of the POST methods of Receiptful API require to send data in JSON format with “Content-Type” header set to “application/json”. Therefore, we add aditional “flag” variable “app_json” to differentiate between two types of POST requests.

Methods galore

Now that we have all of the necessary blocks to send requests, it is time to write actual methods for specific endpoints of the API. I’m not going to showcase all of the methods in this article, but we’ll go through a couple that use POST and one with GET.

Parameters that need to be sent over as GET or POST data are just received and passed as dictionary of function arguments. In places where we need to encode our data as JSON we just use “True” as the first argument to self.post method.

What is so special about “create_receipt” function? It just receives keyword argument instead of positional ones. This is because of enormous list of parameters that can be sent with this method. We just pass it constructed dict of key-values and get the created receipt in response:

Note, that where it’s possible I use “.json()” method at the end of received response to convert Receiptful JSON data to native python dict. In some cases, you would want to just grab “text” of the response as in “resend_receipt” function.

Further improvements

Of course, when you write enterprise-grade module for working with APIs, you must also implement handling of all errors that might be returned. This is typically done by raising custom exceptions that you need to construct (usually in separate “expeptions.py” file). Users would have to just wrap callable method inside try…expect block specifying exact exception that needs to be caught.

Another neat thing about Receiptful API is that it provides special “navigation” keys for lists of objects. They put it in base “meta” objects:

Using this we can easily navigate through list of objects when needed. This is also one cool feature you can implement to make developers that use your module a little bit happier.

--

--