Building a rest API client or SDK as a python package

The best way to learn ways of building your API wrapper / SDK is to see ones that already exist. Here is a list of python api wrappers you can checkout and view. Most if not all of them are already python packages.

Here is a good post on how to test and build an API client / wrapper. In the post the author uses vcrpy as a way to replay stored responses, however they do actually happen the first time. To prevent your tests from ever hitting a real API you should look at Responses.

I also found a few generic wrappers for the requests library that are supposed to make your life easier, but it looked like many were just abstraction for abstraction sake and the closer your are to requests the better.

I did however find uplink which is a python api boilerplate module based on retrofit – which is the goto http client for Android development. I like it and I think it will make my life a bit easier when creating the api wrapper. It is however still in beta. Tapioca is another one, but I didn’t rate it. It arised from this fellow not liking how API wrappers are done and the added abstraction.

As a side note, Braintree doesn’t even make the rest API available, it forces clients to use a client or wrapper built by them mainly to ensure security.

I found uplink hard to work with…it seems as though the further you are from requests the harder your life becomes.

Allowing for a User Provided Session

One of the key things needed when making an API wrapper/client available is letting the user provide their own session. A reason for this is that user could have added additional auth to the API they are connecting to or may be using a different method of auth altogether.

Also, the client may be using an API gateway like kong so the client may need an auth token or some other permission. So it is better to just allow the user to provide their own session – which can then be modified with the session id’s.

So in the class constructor – __init__() method, ensure a session can be set and default it to none. The below example is adapted from the hvac client. eg:

class MyClient(object):
    """My Api Client"""

    def __init__(self, base_uri=DEFAULT_BASE_URI, cert=None, verify=True, timeout=30, proxies=None, session=None):
        """Create a new request adapter instance.

        :param base_uri: Base URL for the Vault instance being addressed.
        :type base_uri: str
        :param cert: Certificates for use in requests sent to the Vault instance. This should be a tuple with the
            certificate and then key.
        :type cert: tuple
        :param verify: Either a boolean to indicate whether TLS verification should be performed when sending requests to Vault,
            or a string pointing at the CA bundle to use for verification. See
        :type verify: Union[bool,str]
        :param timeout: The timeout value for requests sent to Vault.
        :type timeout: int
        :param proxies: Proxies to use when preforming requests.
        :type proxies: dict
        :param session: Optional session object to use when performing request.
        :type session: request.Session
        if not session:
            session = requests.Session()

        self.base_uri = base_uri
        self.token = token
        self.namespace = namespace
        self.session = session
        self.allow_redirects = allow_redirects

        self._kwargs = {
            'cert': cert,
            'verify': verify,
            'timeout': timeout,
            'proxies': proxies,

As you can see in the example above it is not just the session. Other things like SSL verification, the certificate to use for SSL verification and proxies can be passed to the constrator to allow for versatility.