REST is an API that allows developers to perform a set of functions based on exchange of HTTP Requests. For example, Twitter allows you to retrieve tweets from your account without having to use the twitter portal, by means of REST API. Similarly Whatsapp business users can send and receieve messages from their business Whatsapp account via Whatsapp REST API, directly from their applications.

In this tutorial we will build a simple API Client with HTTP Requests library to support the commonly used HTTP Authentication types.

In the below code, we create a class called ‘RestOperations’ and define SendGettReq() and SendPostReq() functions for HTTP GET and HTTP POST capabilities. These functions expect the type of authentication and the attributes that are relevant to that type.

For instance, to be able to authenticate using Simple HTTP Authentication, we need to send username and password attributes with the request.

fork-git

#/usr/bin/python
import requests
from requests.auth import HTTPBasicAuth
from requests.auth import HTTPDigestAuth
from requests_oauthlib import OAuth1

class RestOperations:
    
    def __init__(self, apiEndPoint, **kwargs):
        self.apiEndPoint = apiEndPoint
        self.kwargs = kwargs
    
    def SendGetReq(self):
        auth = self.CallAuth(self.kwargs)
        try:
            RespGetReq = requests.get(self.apiEndPoint, auth = auth)
        except Exception as SendGetReqException:
            print("Exception while sending GetRequest", SendGetReqException)
        return RespGetReq
    
    def SendPostReq(self):
        if 'PostData' not in self.kwargs:
            raise TypeError("request type 'Post' requries PostData")
        else:
            PostData = self.kwargs.get('PostData')
        auth = self.CallAuth(self.kwargs)
        try:
            RespPostReq = requests.post(self.apiEndPoint, PostData, auth = auth)
        except Exception as SendPostReqException:
            print("Exception while sending PostRequest", SendPostReqException)
        return RespPostReq

Further, we will define two more functions CallAuth() and ValidateAuthAttrs(). CallAuth() calls the type of Authentication being requested in the GET and POST requests, whereas the ValidateAuthAttrs() ensures that all the necessary attributes needed to perform the authentication is being provided.

    def CallAuth(self, OptionalAttrs):
        authType = self.ValidateAuthAttrs(OptionalAttrs)
        if not authType:
            auth = None            
        elif authType == 'token':
            auth = HTTPBearerAuth(OptionalAttrs.get('token'))
        elif authType == 'basic':
            auth = HTTPBasicAuth(OptionalAttrs.get('username'), OptionalAttrs.get('password'))
        elif authType  == 'digest':
            auth = HTTPDigestAuth(OptionalAttrs.get('username'), OptionalAttrs.get('password'))
        elif authType  == 'oa1':
            auth = OAuth1(OptionalAttrs.get('AppKey'), OptionalAttrs.get('AppSecret'), OptionalAttrs.get('UserToken'), OptionalAttrs.get('UserSecret'))
        return auth
    
    def ValidateAuthAttrs(self, OptionalAttrs):
        if 'authType' not in OptionalAttrs:
            authType = None
        else:
            if OptionalAttrs.get('authType') not in ['token', 'digest', 'basic', 'oa1']:
                raise ValueError("Unknown authType received", OptionalAttrs.get('authType'))
            else:
                if OptionalAttrs.get('authType') == 'token' and 'token' not in OptionalAttrs:
                    raise ValueError("authType 'token' requires token")
                elif OptionalAttrs.get('authType') == 'basic' and not all(attr in OptionalAttrs for attr in ['username', 'password']):
                    raise ValueError("authType 'basic' requires username, password")
                elif OptionalAttrs.get('authType') == 'digest' and not all(attr in OptionalAttrs for attr in ['username', 'password']):
                    raise ValueError("authType 'digest' requires username, password")
                elif OptionalAttrs.get('authType') == 'oa1' and not all(attr in OptionalAttrs for attr in ['AppKey', 'AppSecret', 'UserToken' 'UserSecret']):
                    raise ValueError("authType 'oa1' requires AppKey, AppSecret, UserToken, UserSecret")
                else:
                    authType = OptionalAttrs.get('authType')
        return authType

HTTP Requests does not support HTTP Bearer authentication. Hence we create a child class to accept a bearer token to be sent in the HTTP Authorization Header, in case HTTP Bearer token authentication is being requested.

class HTTPBearerAuth(requests.auth.AuthBase):
    '''requests() does not support HTTP Bearer tokens authentication, create one'''
    def __init__(self, token):
        self.token = token

    def __eq__(self, other):
        return self.token == getattr(other, 'token', None)

    def __ne__(self, other):
        return not self == other

    def __call__(self, r):
        r.headers['Authorization'] = 'Bearer ' + self.token
        return r

That is all!. RestOperations can be instantiated to send GET or POST requests as in the following example.

from RestOperations import RestOperations
rest = RestOperations('https://someurl.com/api/', authType = 'token', token = 'gXE1CWifeADQyCK7TfuxKuns1_GjFthFT2sB')
print(rest.SendGetReq().text)