How to build a GraphQL wrapper for a RESTful API in Python
I wanted to give GraphQL a shot for a while now. After all, the cool kids at Github are doing it, so I wanted to learn what all the hype is all about. From what I’ve seen so far it looks like GraphQL would likely supersede REST the same way SOAP got obsoleted by more lightweight stateless JSON-based APIs. From what I’ve seen so far, one of the biggest advantages in for my work would be the following:
Rapid iteration on the frontend by decoupling client from server
You don’t need to make any modifications on the API if you decided that you want to access different data on the frontend, as you can specify declaratively what data you need on, rather than how to get it.
If you want to learn more about GraphQL and key differences with REST, I highly recommend this article.
For the purpose of this tutorial, I’m using the following components:
- Airbnb API via a Python wrapper as an API to be wrapped
- Graphene library for the backend
- Flask and Flask GraphQL for the API backend
In this tutorial, I’ll show you how to define schema on your backend and transform JSON into GraphQL models.
Concretely, we would query reviews for a given Airbnb listing as an example.
Below is a sample of a response we get from our API:
As you can see we get an array of reviews in
reviews key in our JSON dictionary.
Now what I would love to do is just to be able to automatically map all the keys of a given review from the JSON payload to respective keys in our internal data model. Unfortunately, there is no such way as far as I know of, so we’d have to define our data models manually.
As you can see in the previous JSON response, we have a few nested objects inside our review:
listing. To transform those inner structures, we’d want to create additional classes. From the look of it
recipient have the same format, so we can combine them in
User class, and we would create another class for
Listing as well.
Now we can refer those internal structures from
Review simply as
The only thing left to do is to define respective data types for the rest of the fields. GraphQL and Graphene provide the following base scalar types:
String, Int, Float, Boolean, ID. For more information about defining custom data types, read here.
That said, I’ve ended up with the following schema defined with Graphene:
When it comes to interfacing our data model to the JSON and doing the transformation of the payload to python objects, here is where the things get sort of confusing.
Our goal is to define the following GraphQL query, which fetches reviews for a given listing, for example, to fetch all comments for the listing with id 1238125, we’d use the following query:
To represent the query above with a Graphene, we’d need to define
Query class as follows:
Here we map the field
reviews from our JSON response to a List of Review objects defined earlier. We also specify that our GraphQL query would have a single non-optional parameter:
Now we need to map this field to an API call. To do that we need to define a resolver which would actually do the network call. Resolvers are static methods defined on Graphene object type classes which have the following format by default:
Converting JSON to Python objects
The only thing left to do is to convert our JSON dictionary to objects, so that instead of calling
reviews["role"] we would be able to call
reviews.role. According to Graphene design, objects are expected to be returned by a resolver. So here is what we are going to do: serialize our JSON, then deserialize it into objects using object_hook which would convert everything into named tuples:
Finally, here’s how our final resolver would look like:
api_call actually calls the RESTful API using
id parameter from our GraphQL query.
Putting it all together
Great! We finally figured out how to map our RESTful API to GraphQL. Now I’ll show you how to build a simple Flask-based backend serving that GraphQL goodness.
We can put all of the scheme-related code in
schema.py and create a simple Flask app only with a few lines of code:
Here I’m referencing
schema.py and enabling GraphiQL which works as an interactive browser for your GraphQL API.
Now, you can start the app, go to http://localhost:5000/graphiql and try your brand new GraphQL API!
I’ve deployed the app to Heroku, so that you can try it yourself!
Finally, all of the code used in this tutorial is available for you on Github for further tinkering. Have fun!