Derek Stegelman

Wrapping Your API Calls for Fun and Profit

The last few months I've been working on fixing up our applications at K-State and how they interact with other custom built and off the shelf software. One of our common practices on the web team is to create applications that consume data from other organizations on campus, manipulate it, display it, etc. One of the things I noticed early on was that we would use the same boilerplate code to generate and get responses from various systems. None of the calls were tied together, and we often used the same or similar data in multiple apps. Something had to be done.

We decided to create a standalone python library that brought all these systems together in a way where developers could easily use existing integrations and create brand new ones.

Why?

At K-State we use a lot of different systems and they all need to interact with one another at some level. One of the main tasks of my team is use APIs from these various systems to either push or pull data. Some of these systems use SOAP XML as a format while others use JSON based REST services.

Having a consistent and easy way to consume those services in our Django applications is of critical importance to our mission and goals at the university.

Benefits

Some of the features we've built into our library include:

  • Supports both SOAP and REST based calls. We use a simple API base class and then extend that to form base SOAP and REST classes that each override or extend functionality.
  • Supports different authentication schemes.
  • Integrates endpoints from over 20 different departments or campus organizations.
  • Full test suite with CI from Jenkins.

Base API

We created a base API class structure that does a few different things for us that we need all over the place. The base class:

  • Sets up auth for the underlying call.
  • Sets up and bootstraps settings, allowing overrides.
  • Patches a few customizations that we require.

Defining External Calls

When a developer wants to make an API call they want something that feels natural and flows well. Instead of the usual boilerplate involved with setting up requests or SUDS they can simply import the API and make a call.

from kstate.api import KstateAPI

api = KstateAPI()

result = api.get_affiliations(eid='someone')

Under the covers we have this initial call.

def get_affiliations(self, eid, **kwargs):
    """
    Get Affiliations Service

    :param e_id: eID of user to get affiliations for
    :return list: List of Affiliation Strings

    Example::

    api = KstateAPI()

    affiliations = api.get_affiliations(eid='someuser')

    Returns::

    [u'EMPLOYEE_CURRENT', u'STUDENT_FORMER']

    """
    return GetAffiliations(settings=self.settings, **kwargs).call(eID=eid, **kwargs)

Further down each API call has its own class that inherits from some common functionality that each method somewhat shares. At this level things like Authentication and methods for REST and SOAP are used. This level of abstraction allows us to present developers with the same interface regardless of the underlying API structure. SOAP requests and REST API endpoints look the same to a developer consuming this library.

Under the covers our base is simply a collection of mixins and base classes that build up to a very small amount of code that needs to be written in order to add new API endpoints to the library.

Unfortunately, most of this code is somewhat proprietary so this isn't an open source project. However, if you have specific comments or are interested in this design for your project, drop me a line.