Elegant RESTful API client in Python
@xav-b|November 30, 2015 (9y ago)3 views
Product Hunt addicts like me might have noticed how often a "developer" tab was available on landing pages. More and more modern products offer a special entry point tailored for coders who want deeper interaction, beyond standard end-user experience. Twitter, Myo, Estimote are great examples of technologies an engineer could leverage for its own tool/product.
And Application Programming Interfaces (API) make it possible. Companies design them as a communication contract between the developer and their product. We can discern Representational State Transfer APIs (RESTful) from programmatic ones. The latter usually offer deeper technical integration, while the former tries to abstract most of the product's complexity behind intuitive remote resources (more on that later).
The resulting simplicity owes a lot to the HTTP protocol and turns out to be trickier than one think. Both RESTful servers and clients often underestimates the value of HTTP historical rules or the challenges behind network failures.
I will dump in this article my last experience in building an HTTP+JSON API client. We are going to build a small framework in python to interact with well-designed third party services. One should get out of it a consistent starting point for new projects, like remotely controlling its car !
Stack and Context
Before diving in, let's state an important assumption : APIs our client will call are well designed. They enforce RFC standards, conventions and consistent resources. Sometimes, however, real world throws at us ugly interfaces. Always read the documentation (if any) and deal with it.
The choice of Python should be seen as a minor implementation consideration. Nevertheless, it will bring us the powerful requests package and a nice repl to manually explore remote services. Its popularity also suggests we are likely to be able to integrate our future package in a future project.
To keep things practical, requests will hit Consul HTTP endpoints, providing us with a handy interface for our infrastructure.
Consul, as a whole, it is a tool for discovering and configuring services in your infrastructure.
Just download the appropriate binary, move it in your $PATH
and start a
new server :
We also need python 3.4 or 2.7
, pip installed and, then, to download the
single dependency we mentioned earlier with pip install requests==2.7.0
.
Now let's have a conversation with an API !
Sending requests
APIs exposes resources for manipulation through HTTP verbs. Say we need to
retrieve nodes in our cluster, Consul documentation requires us to perform
a GET /v1/catalog/nodes
.
Providing consul is running on the same host, we get the following result.
Awesome : a few lines of code gave us a really convenient access to Consul
information. Let's leverage OOP to abstract further the nodes
resource.
Mapping resources
The idea is to consider a Catalog
class whose attributes are Consul API
resources. A little bit of Python magic offers an elegant way to achieve that.
It might seem a little cryptic if you are not familiar with built-in Python's object methods but the usage is crystal clear :
The really nice benefit with this approach is that we become very productive in
supporting new resources. Just rename the previous class ClientFactory
and
profit.
But... what if the resource we call does not exist ? And, although we provide an
header with Accept: application/json
, what if we actually don't get back a
JSON
object or reach our rate limit ?
Reading responses
Let's challenge our current implementation against those questions.
Well that's not safe at all. We're going to wrap our HTTP calls with a decorator in charge of inspecting the API response.
This implementation stills require us to check for errors instead of disposing of the data right away. But we are dealing with network and unexpected failures will happen. Being aware of them without crashing or wrapping every resources with try/catch is a working compromise.
Conslusion
We just covered an opinionated python abstraction for programmatically expose remote resources. Subclassing the objects above allows one to quickly interact with new services, through command line tools or interactive prompt.
Yet, we only worked with the GET
method. Most of the APIs allow resources
deletion (DELETE
), update (PUT
) or creation (POST
) to name a few HTTP
verbs. Other future work could involve :
- authentification
- smarter HTTP code handler when dealing with
forbidden
,rate limiting
,internal server error
responses
Given the incredible services that emerged lately (IBM Watson, Docker, ...), building API clients is a more and more productive option to develop innovative projects.