GraphQL for the Beginner Pythonistas
Graphql is all the rage since it was released to the public from Facebook in 2015 “GraphQL: A data query language”. Numerous clients/servers in varying degrees of maturity have appeared. The tangible benefit of Graphql is to reduce the storm of REST calls to compose the parts of an object. This way the API is not abused to behave as a query language. We use SQL to send queries to the database, we send GraphQL to query whole objects to a server that aggregates the parts of the result not from a database only, but from various sources like third-party services too.
This article targets the beginner Pythonista. Just the bare basics but with the ambition to help the beginner blossom. We target the typical Flask / SQLAlchemy duo through the wonderful Graphene library . We also utilize the flask-graphql library from the same master project. The purpose of this article is modest and builds upon the excellent Flask tutorial that is a prerequisite and from which we heavily borrowed. Grab you favorite text editor or IDE and lets get started. I used Python 3.8.5 during development, and I manually tested the app. Verified to work with Python 3.9.0 and there is Part 2 (Testing).
Code and Dependencies
You can grab the code from my repo:
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…
The specific combination of packages in the requirements.txt was a successful one when this article was written. Hopefully people can use latest packages in the future.
Lets outline here from the beginning what we are trying to achieve. We aim to throw away the html layers of the Flask tutorial app and instead CRUD posts and users through GraphQL. We still use the SQLite database of the tutorial app but instead we use SQLAlchemy as an ORM both for initialization and access. We will not write automated tests in this article. But in any case we need to be able to manually test what we have achieve so far. To this purpose we use the interactive GraphQL client that runs as part of our server to view our schema and to execute CRUD actions. There maybe more automated ways to achieve our purpose. These are out of scope for this article.
Dealing with the database
As a first step we port the init-db script from the original Flask tutorial to SQLAlchemy Orm. We will use the orm objects (DAO) in order to keep our application OO as much as possible. The script is used through CLI to initialize the database as a click application. The concepts we use could be found here for example. If you are new to SQL Alchemy ORM, stop now and come back after reading that article.
Since we use the ORM, the first step is to create an engine instead of the DB of the original tutorial. Through the engine we will create sessions to CRUD objects in the database. Take a close look on the context manager. What is this yield doing there? The first function is used because I use sqlite and the foreign key support is not on by default. I had to consult the documentation
SQLAlchemy 1.3 Documentation
Support for the SQLite database. The following dialect/DBAPI options are available. Please refer to individual DBAPI…
The next modification is the initialization. We throw away any SQL scripts. In a typical database we use migrations to populate the database. Here we keep things simple. We inline the objects. But in reality the objects could live in a serialization format outside our application. E.g. JSON is the first thing that comes to mind. To this end, we need to describe the objects that mediate the actions to the database and allow the LUW pattern.
!Warning! In order to get the cascaded delete right, after some fighting, I had to consult this excellent explanation:
SQLAlchemy: cascade delete
Pretty old post, but I just spent an hour or two on this, so I wanted to share my finding, especially since some of the…
Now we have all the facilities to initialize our database.
The easy part is done. We proceed to model the CRUD actions with GraphQL.
To follow the discussion keep in a separate tab the excellent GraphQL tutorial. Now that we have objects to model what goes in and out to our database as an object repository we need to make the corresponding objects that specify the types our GraphQL works with. We also provide conversion functions that translate from ORM land to GraphQL land. The GraphQL objects are prefixed with GQL.
The convert functions just take a DAO object and transform it to a GraphQL object. The interesting part here is that the object fields are initialized with objects that specifiy the schema types. So a string field is initialized to a graphene.String object. the same holds for Int fields. An object field is initialized with a graphene.Field object that its constructor takes as parameter the class of the GraphQL object. There are many common types that users should utilize but these are the principles.
The first GraphQL query
We proceed to create our Query, the R part of CRUD. We aim to be able to query all users, all posts (this is why we initialized the database with sample objects) , a particular user by username or a post by title. We need to create a container object, called Query that carries all these queries. All of them actually.
Everytime we ask one of them (or more than one) and since the rest are not used they do not participate in the result formation process. The query is resolved by the server that acts as a “database” and can assemble the object by retrieving its parts from various databases, from REST services or even by polling a peripheral port of the computer. In this post we focus in assembling our resolution from the database. We just make calls through SQLAlchemy to the database to retrieve objects.
Executing queries interactively
Let us see how it looks. We run the application according to the README.md in the repository. Navigating to http://127.0.0.1:5000/graphql we arrive at a beautiful prompt installed by the GraphiQL package. It is actually an interactive prompt for executing GraphQL statements. We also have implemented some mutations. For now let’s focus on the Query part.
Click on it. On the left panel we can enter our query. On the rightmost panel we view all the possible subqueries nicely typed. Lets harvest the power of Graphql. Our first query amounts to viewing what we have inserted to the database by default for the posts. See the next gist.
We can just describe what we expect from every post. It is like minimal SQL. While you type the gist, look how nicely it does autocompletion based on our small CRUD universe of types.
After executing it we see that it brings us what we asked. Nothing more, nothing less.
Feel free to experiment by exploring the interactive repl and reading the Graphql documentation.
We did not implement all the possible mutations. But it is a good exercise to implement the U part of the CRUD gang. Here is the C & D mutations we created.
We will create a post for an existing user. Pay attention to the Arguments class that is a placeholder for arguments, that they will be propagated to the mutate action. The mutation action returns something. Here we return the whole post object. Again, I should notice that the official documentation is a prerequisite for mutations. But one can use only the id part. A picture is worth a thousand words . Take a close look at the south west “Query Variables” tab that appears on pressing.
through the gist
Another more direct way is shown here
through the gist
By executing our mutation we got back the whole post. Run again the allposts query we previously mentioned in order to see the new insertion.
I will not repeat the famous saying about big journeys and small steps. Hopefully this article has served its purpose and lured you into the convenience of GraphQL. Python with its numerous frameworks and packages make our life considerable easier. Feel free to checkout the code, experiment, extend, ….. and also report that bug :-)