top of page
  • Writer's pictureTaylor Etheredge

Python Class Inheritance

Updated: Nov 10, 2023

Today we are going to learn how Python inheritance works and how to setup a base class that interacts with an external API. The subclass or child class that inherits from the base class will provide the specifics that the external API needs. The base class will provide the framework for how those calls are made. Let's get to it.


First we need to create the base or super class that describes how the connections to the external API are made. We are going to be using the requests package in Python so install that first.


pip install requests

Create a class that holds our credentials in a separate file called creds.py:


import sys
import os

class Creds():
    def __init__(self):
        pass
        
    def get_api_token(self):
        return os.environ.get("TOKEN", 'test-token')


Here is how the entire base class is setup. Put this code in a file called base_api_client.py. I will explain what all this is doing here in a bit, but wanted to display it all here so that you can easily see it all at once.



import requests
from creds import Creds

class BaseApiClient():
    def __init__(self, base_url = None, sess = None):
        base_url = self.url() if base_url is None else base_url
        self.base_url = base_url
        self.auth = Creds()
        sess = requests.Session() if sess is None else sess
        self.sess = sess

    def url(self):
        match self.__repr__():
            case 'Example':
                return 'https://example.com/'
            case _:
                return None

    def headers(self):
        return {}

    def api_get(self, route, query_params = None):
        if query_params is None:
            query_params = ''

        with self.sess as client:
            try:
                resp = client.get(
                    self.base_url+route,
                    params=query_params,
                    headers=self.headers(),
                )
                resp.raise_for_status()
            except requests.exceptions.HTTPError as err:
                print("Http Error:", err)
                raise err
            except requests.exceptions.RequestException as err:
                print("Error:", err)
                raise err
           
        return resp.json()

First we import the necessary packages and files this class needs. Then we create the class of BaseApiClient. This class is initialized with two parameters that are optional and set to None by default. They are there for testing purposes to inject dependencies for the mocked up API calls. We are not going to cover that here, but I have a blog post on that topic that you can read. So what is all this stuff happening in the init method. Well we set the base_url variable to call the method self.url() if the base_url is None, otherwise set it to the url passed in during object initialization. The self.url() method is checking to see what the subclass is to in order to determine what url needs to be assigned to self.base_url. The match statement is calling self.__repr__() from the child class or the derived class. This method must be defined in each child class in order to determine what the base url is for that particular external API. Then we create a Creds object and a requests.Session() object if one does not already exist. The next method headers, just returns an empty dictionary. This is because the subclass will have different headers for each external API, however if an external API does not require any headers, then it will default to an empty dictionary. Next is the meat of this class. This is where the individual types of api calls will go. The BaseApiClient class should only care about how to connect to the external API, not all the details of the exact route to connect to or the exact parameters the API needs or any other information in regards to that. It only cares about how to setup the connection, the child class will give the details necessary for the API to understand and return. I talk about how to use the requests package in a prior blog post, so if you are not familiar with it please give that a read first. What the api_get method is doing, is connecting to the external API based on the details that are passed into the method. These details are passed in from the child class. If the connection is successful and data is returned successfully then it will return the data from the API. If there is an issue of any kind it will raise an error, pretty simple right? So that is the BaseApiClient class explained and I hope that makes sense. We will now move onto the creation of the child class and how it works with the BaseApiClient class in getting data from the external API.


So now this is what the child class looks like, and again I will explain it soon.



from base_api_client import BaseApiClient
from datetime import date

class ExampleApi(BaseApiClient):
    def __init__(self, url = None):
        BaseApiClient.__init__(self, base_url = url)

    def __repr__(self):
        return "Example"

    def headers(self):
        return {'JWT': self.auth.get_api_token()}

    def devices_created_per_year(self, date):
        query_params = {
            "date": str(date.today())
            "sort": "created",
        }

        return self.api_get('devices',
                            query_params = query_params)

First we import the base class an any other packages that we need in this case. Then the child class of ExampleApi is created and the specification of the BaseApiClient is in parenthesis. This is how a class inherits another class in Python. You can specify multiple classes in the parenthesis, however in our case we only need the one class to inherit from. As you can see the init method of the child class is a bit different. Here we only pass in a url if need be, again this is for dependency of the testing environment. The next part is pretty cool. This is where we call the init method of the parent class as in our case BaseApiClient and pass in the url. As you see above in the BaseApiClass, a lot more than the url is being set in its init method. The cool thing is that the child class inherits everything the parent class has to offer, that means all it attributes and methods. So the child class now has access to self.auth for example and so on. The next method __repr__ is the special method that each child class needs in order for the base class to determine what endpoint to hit. Here we return "Example" so the base class will know to get the url that matches "Example". Next is the headers method that is also specified in the base class. This is another cool concept too. Here we are overriding the headers method in the base class and setting it to be the header that the example.com needs in order for proper authentication to occur. Finally we define the custom method this child class needs in order to get the necessary details from the example.com API. As you can see the method takes in an argument that the certain API endpoint needs and then builds the query parameters that are necessary with that argument. The return statement is where this all comes together. Here we call the method from the base class called api_get with the specific details that the example.com API needs. This is how the details get passed into the base class and then out to the external API.


I hope you now have a much better understanding of how Python class inheritance works. Please stay tuned for more content on Python. I hope to include some posts on working with routers and switches using Python in the foreseeable future.

13 views0 comments

留言


bottom of page