avatarYanick Andrade

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

7030

Abstract

our queries.</p><p id="c111">In our scenario we’re using <b>fragments </b>to compare two products by analyzing their comments:</p><figure id="812b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*oLatwbkIgfqPhgiLgxUFBA.png"><figcaption></figcaption></figure><p id="8c7a">But imagine that we want to use this same function on our client side, but we have no interest in the comments. GraphQL has a feature named @Include that works just like a function, receiving an argument and only including the fields if the argument is <i>True:</i></p><figure id="a945"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*E1_mDeVMsRKXikkdBIWrzg.png"><figcaption>GraphQL @Include</figcaption></figure><p id="5e3f">There is also that @Skip literally skips the fields if the argument is <i>True. </i>Take the example above where we use <b>include</b>, we might want to skip comments in certain views in our system, and we want to reuse our function, this can be easily achieved:</p><figure id="15d2"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*pW5LjJtk764N3QmQtE2KNA.png"><figcaption>GraphQL @Skip</figcaption></figure><p id="b377">Another interesting feature is multiple queries in a single request. In some applications, you might have a view that displays multiple pieces of information from different entities. In Rest the two approaches that might occur are to create a single endpoint to fetch all this information or create multiple endpoints each one designed to return specific information. In GraphQL as long as you have your API returning data for your entities, you can design a query from the client side to fetch the data as needed for your entities in a single request to the API:</p><figure id="a0a5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*IwyzSuOOgwvbOfIAc1HeeA.png"><figcaption>Multiple Query single Request</figcaption></figure><h1 id="2e56">Coding Time</h1><figure id="eae4"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*lAv1Z2Sb2STI-frAPc6Smw.jpeg"><figcaption>Photo by <a href="https://unsplash.com/@ikukevk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Kevin Ku</a> on <a href="https://unsplash.com/s/photos/coding-time?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p id="8f9e">First, we have to set up our code environment by installing Python, Django, and virtualenv. <a href="https://github.com/YanickJair/graphene-demo"><b>The project can be found in my GitHub repository</b></a>.</p> <figure id="0dde"> <div> <div>

            <iframe class="gist-iframe" src="/gist/YanickJair/5a631e1ccd5cf36563f977b108083a42.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="ee62">After installing everything, we can create our API and install the dependencies. To create a Django project go to your root folder or where you want the project to be stored and execute the following commands. The last command we’ll only execute after copying this requirements below into a <i>requirements.txt</i> file inside the project root folder:</p>
    <figure id="9522">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/1dc35a9116356d16829863edbbbce41a.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure>
    <figure id="1af4">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/e4ee735317d6e767b50edf1c68fa4614.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="59e2">Add the <i>demo </i>and<i> graphene-django </i>to INSTALLED_APPS in graphenedemo/settings.py:</p>
    <figure id="63a0">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/4ea8a29844d748da6399646e93250f07.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="e13e">Everything is OK, now let’s have some fun coding our API. First, we start with our models, inside your project you have a <i>demo </i>app folder, <i>cd</i> inside it and you will see a <i>models.py</i> file:</p>
    <figure id="05e1">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/5a3ae5f6cbbfdf007aee20678948495f.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="ea68">Super!! Now let’s create a new folder inside our app and name it <i>gql. </i>Inside this folder, we are going to write all the GraphQL logic.</p><p id="8da5">With the folder created, <i>cd</i> into it and create a new file and name it node.py. Nodes are the GraphQL representation of our models in Django. Inside our node object we can define a dictionary filter that we would want to have in our queries:</p>
    <figure id="5050">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/169ccad2b7f7bf513174f28227a4b573.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="b35d">The last function in the node.py file, <i>get_node_id</i>, is to get the object number Id. Because we’re using Graphene Relay Node, when we make a query we don’t get the object ID in digits, instead, we get an encoded Id to work with. And when we want to make any action on top of that object in our DB we need to decode the Id to get the digit representation. The assert is to make sure that the Id we’re decoding is indeed what we want.</p><p id="4e19">We focus most of the article talking about how GraphQL is good for fetching data but we never said a word about creating data. In GraphQL writing, data is possible through Mutation. A mutation in Graphene is made by making all of our classes a subclass <code>relay.ClientIDMutation.</code> We will define our subclasses inside a <i>gql/resolvers.py</i> file:</p>
    <figure id="8843">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/045dccfa98a6799e28a34453a38d047c.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="f2c5">Inside our resolvers.py we have the following sub

Options

classes:</p><ol><li>CreateProductCategory: Create a new category for products. It has 1 mandatory input — name (String)</li><li>CreateProduct: Create a new product. It has 3 mandatory inputs: name (String), category (ID), and price (Float). Before creating a product we first have to decode the category’s ID using the defined function inside nodes.py — get_node_id. After decoding the ID we can filter to see if the category actually exists, if so, we create the Product.</li><li>ManageFavorites: Add or Remove a product from the favorite list. It has 3 mandatory inputs: user (ID), product (ID), and action (Enum). We do the same thing we did with category ID in CreateProduct with input user and product, if everything is fine we check which action was requested and we either add a product to our favorite or remove it.</li><li>Comment: Add a new user’s comment to a product. It receives two mandatory inputs: user (ID) and product (ID). It first checks if the user and product exist and then saves the comment.</li></ol><p id="1657">Done that, now we can create our Query and Mutation object that we’ll later connect to our schema that will make them available in our API.</p><p id="2dc8">Query object is where all our “endpoints” functions for reading or fetching data will be. It’s very straightforward, in general, we will have two lines of code for each entity (i.e. product and products), one bringing all the data with possibilities to filter the way we want and another one receiving an ID as input and returning the matching data.</p> <figure id="a62b"> <div> <div>

            <iframe class="gist-iframe" src="/gist/YanickJair/f1dd4329f03f27b871fce662dcc34497.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="dcba">The <b>DjangoFilterConnectionField</b> we’re using allows us to make our queries (i.e. users) even more powerful enabling us to filter with multiple options besides the fields in our models and the returning result is a list of objects.</p><p id="1f30">The <b>graphene.relay.Node.Field </b>allows us to make a query in a single object (i.e. user) by passing an ID as input.</p><figure id="8d47"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*waG7HtYzMbjIX2wnQv2UTw.png"><figcaption>Query — GraphQL</figcaption></figure><p id="d65c">Mutation object is where we call our resolvers subclasses to write in our API. Just like the Query object, it’s very straightforward, it contains the endpoints for writing data.</p>
    <figure id="a915">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/72778636fbc9e4af6425dd390f7a7669.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="7b0d">Now we can pack everything into our Schema. Browse to the project root folder and enter the <i>graphenedemo</i> folder and create the <i>schema.py</i> file and paste the following code:</p>
    <figure id="e8c8">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/cc5b720f4138437e867555f12f43295d.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="8c78">Now we can migrate our models to our Database. We will use SQLite, the default that comes with Django. We will also need to create a new superuser to test our API properly:</p>
    <figure id="07b1">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/28429abd36c47642dd1489e2a9bd30b5.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="64ab">Configuring the URL. To enable the use of the GraphiQL playground we’re going to use <b>GraphQLView </b>object’s function <i>as_view</i> and enable it by setting <i>graphiql</i> parameter to True, the second parameter is our Schema object already defined (above):</p>
    <figure id="2666">
        <div>
          <div>
            
            <iframe class="gist-iframe" src="/gist/YanickJair/8993f7dacc774545d91da982172e1375.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="32ea">And that’s all folks. Now we can go ahead and run our Django API by running this command: <i>python mana.py runserver </i>and if everything is fine you should see this in you <a href="http://127.0.0.1:8000/graphql/">http://127.0.0.1:8000/graphql/</a>:</p><figure id="d34d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*365R-0Ny_Ug-ZkCj6Kys1w.png"><figcaption>GraphiQL Playground</figcaption></figure><p id="b908">To avoid making this article very extensive I’ll include a screen record video of the API:</p>
    <figure id="5d58">
        <div>
          <div>
            <img class="ratio" src="http://placehold.it/16x9">
            <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FTOnKqrilY3Q%3Fstart%3D223%26feature%3Doembed%26start%3D223&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DTOnKqrilY3Q&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FTOnKqrilY3Q%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" allowfullscreen="" frameborder="0" height="480" width="854">
          </div>
        </div>
    </figure></iframe></div></div></figure><p id="2771">And with that, I “close” this article. Hope everyone enjoys it and I would like to hear from you.</p><h1 id="94e4">PlainEnglish.io 🚀</h1><p id="1038"><i>Thank you for being a part of the In Plain English community! Before you go:</i></p><ul><li><i>Be sure to <b>clap</b> and <b>follow</b> the writer</i><b>️</b></li><li><i>Learn how you can also <a href="https://plainenglish.io/blog/how-to-write-for-in-plain-english"><b>write for In Plain English</b></a>️</i></li><li><i>Follow us: <a href="https://twitter.com/inPlainEngHQ"><b>X</b></a><b> | <a href="https://www.linkedin.com/company/inplainenglish/">LinkedIn</a> | <a href="https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw">YouTube</a> | <a href="https://discord.gg/in-plain-english-709094664682340443">Discord</a> | <a href="https://newsletter.plainenglish.io/">Newsletter</a></b></i></li><li><i>Visit our other platforms: <a href="https://stackademic.com/"><b>Stackademic</b></a><b> | <a href="https://cofeed.app/">CoFeed</a> | <a href="https://venturemagazine.net/">Venture</a></b></i></li></ul></article></body>

GraphQL with Python

Using Graphene to build a Django API

A few weeks ago I wrote an article discussing using GrahpQL. In that article, the stack used was JavaScript (Node Js and TypeScript) to develop the API. “I never had a chance” to get into details of the use case or the GraphQL concept per se.

GraphQL is a query language developed by Facebook and went public in 2015. “GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more” — https://graphql.org/

It provides a standard way to:

1. describe data provided by a server in a statically typed Schema

2. request data in a Query which exactly describes your data requirements and

3. receive data in a Response containing only the data you requested.

In this article, I’m going to use Python’s framework Django and Graphene-Django, which is a library built on top of Graphene, a library for making GraphQL APIs in Python quickly.

Before anything, we’re going to see our scenario and why GraphQL can be a suitable replacement for RESTful API in this case. I’m not saying that GraphQL is better than REST, I’m just pointing out why in this scenario it can be a better option for us.

Let’s assume we have an API where we can create products, and users can add to their favorite list and can comment on our product.

Let’s take a close look at our Entity-Relationship model for our API.

ER

Because GraphQL is based on the concept of Graph, where nodes are connected to each other by a line that we call edge, we can transform our ER into a graph:

Graph of our Models

Each node is connected to another node via an edge, and Graphene uses this concept of “Edges” and “Nodes” to organize the relationships internally. When we make a query on a user for instance, and we try to get a user’s favorite list, we get an edge object out of the box which includes a list of nodes, each node representing a favorite item in the Data Base.

Now let’s imagine that we want to get a user favorite product. Based on our ER, we can think about some possible endpoints that we might want to have in a Rest based API to make it possible:

As we can see we have two endpoints, one that returns a list of users, and another one that returns a list of favorite products given a user’s Id. Now let’s see how we could do that using GraphQL:

User Query — GraphQL

PS: Notice how we manage to fetch only the first 1 item in our favorite products. That is a built-in feature that comes with Graphene. Besides fetching the first x we can also fetch the last x.

Comparing the two APIs we can see that using GraphQL it was possible to bring the user’s information plus his/her favorite products all in a single request. Also, if we look closely we can also see that it was possible to bring product information including his category. But what if we wanted just the user’s information only? We don’t want his/her favorite products, just his/her personal information. In Rest, you might have to create another endpoint to facilitate this task, but with GraphQL you don’t have to do this, in the same endpoint we got all the previous information, we can get only the user’s information.

User Information — GraphQL

All those queries above have the same endpoint and the same code. We just are querying the data we need the way we need it. Do you know what the best part is? A single line of code.

User “Endpoint” — GraphQL

Let’s think about our products, we would like to get our products and list them somewhere, we might want to list only the product’s information or we might want to list a product’s information plus its comments. Using Rest the simple way to solve this would be to create an endpoint to get a product’s information including all comments related to the product, but we might have some use cases in which we don’t need a product’s comment list, we would still get all this information from the server for nothing.

Another approach would be creating two endpoints: one to get only the product’s information and another one to bring its comments:

Product and related comments query — RESTful API

Imagine for every endpoint that you might want to make it simpler to only get the data you need for each situation you might encounter. It won’t be easy. First, because we don’t always know if we won’t have to build another component or view in our application that will use our data, second our code can become very complex if we add a new endpoint for every situation or if we make a code to return all related data just so we don’t have to create a new endpoint.

You shall fear nothing my friend, GraphQL is here to save the day.

Now imagine that you have a screen to compare two users side-by-side, showing their attributes, maybe their favorite products, etc. GraphQL allows us to do this by using Fragments. Fragments are “reusable units” that you can include in your queries.

In our scenario we’re using fragments to compare two products by analyzing their comments:

But imagine that we want to use this same function on our client side, but we have no interest in the comments. GraphQL has a feature named @Include that works just like a function, receiving an argument and only including the fields if the argument is True:

GraphQL @Include

There is also that @Skip literally skips the fields if the argument is True. Take the example above where we use include, we might want to skip comments in certain views in our system, and we want to reuse our function, this can be easily achieved:

GraphQL @Skip

Another interesting feature is multiple queries in a single request. In some applications, you might have a view that displays multiple pieces of information from different entities. In Rest the two approaches that might occur are to create a single endpoint to fetch all this information or create multiple endpoints each one designed to return specific information. In GraphQL as long as you have your API returning data for your entities, you can design a query from the client side to fetch the data as needed for your entities in a single request to the API:

Multiple Query single Request

Coding Time

Photo by Kevin Ku on Unsplash

First, we have to set up our code environment by installing Python, Django, and virtualenv. The project can be found in my GitHub repository.

After installing everything, we can create our API and install the dependencies. To create a Django project go to your root folder or where you want the project to be stored and execute the following commands. The last command we’ll only execute after copying this requirements below into a requirements.txt file inside the project root folder:

Add the demo and graphene-django to INSTALLED_APPS in graphenedemo/settings.py:

Everything is OK, now let’s have some fun coding our API. First, we start with our models, inside your project you have a demo app folder, cd inside it and you will see a models.py file:

Super!! Now let’s create a new folder inside our app and name it gql. Inside this folder, we are going to write all the GraphQL logic.

With the folder created, cd into it and create a new file and name it node.py. Nodes are the GraphQL representation of our models in Django. Inside our node object we can define a dictionary filter that we would want to have in our queries:

The last function in the node.py file, get_node_id, is to get the object number Id. Because we’re using Graphene Relay Node, when we make a query we don’t get the object ID in digits, instead, we get an encoded Id to work with. And when we want to make any action on top of that object in our DB we need to decode the Id to get the digit representation. The assert is to make sure that the Id we’re decoding is indeed what we want.

We focus most of the article talking about how GraphQL is good for fetching data but we never said a word about creating data. In GraphQL writing, data is possible through Mutation. A mutation in Graphene is made by making all of our classes a subclass relay.ClientIDMutation. We will define our subclasses inside a gql/resolvers.py file:

Inside our resolvers.py we have the following subclasses:

  1. CreateProductCategory: Create a new category for products. It has 1 mandatory input — name (String)
  2. CreateProduct: Create a new product. It has 3 mandatory inputs: name (String), category (ID), and price (Float). Before creating a product we first have to decode the category’s ID using the defined function inside nodes.py — get_node_id. After decoding the ID we can filter to see if the category actually exists, if so, we create the Product.
  3. ManageFavorites: Add or Remove a product from the favorite list. It has 3 mandatory inputs: user (ID), product (ID), and action (Enum). We do the same thing we did with category ID in CreateProduct with input user and product, if everything is fine we check which action was requested and we either add a product to our favorite or remove it.
  4. Comment: Add a new user’s comment to a product. It receives two mandatory inputs: user (ID) and product (ID). It first checks if the user and product exist and then saves the comment.

Done that, now we can create our Query and Mutation object that we’ll later connect to our schema that will make them available in our API.

Query object is where all our “endpoints” functions for reading or fetching data will be. It’s very straightforward, in general, we will have two lines of code for each entity (i.e. product and products), one bringing all the data with possibilities to filter the way we want and another one receiving an ID as input and returning the matching data.

The DjangoFilterConnectionField we’re using allows us to make our queries (i.e. users) even more powerful enabling us to filter with multiple options besides the fields in our models and the returning result is a list of objects.

The graphene.relay.Node.Field allows us to make a query in a single object (i.e. user) by passing an ID as input.

Query — GraphQL

Mutation object is where we call our resolvers subclasses to write in our API. Just like the Query object, it’s very straightforward, it contains the endpoints for writing data.

Now we can pack everything into our Schema. Browse to the project root folder and enter the graphenedemo folder and create the schema.py file and paste the following code:

Now we can migrate our models to our Database. We will use SQLite, the default that comes with Django. We will also need to create a new superuser to test our API properly:

Configuring the URL. To enable the use of the GraphiQL playground we’re going to use GraphQLView object’s function as_view and enable it by setting graphiql parameter to True, the second parameter is our Schema object already defined (above):

And that’s all folks. Now we can go ahead and run our Django API by running this command: python mana.py runserver and if everything is fine you should see this in you http://127.0.0.1:8000/graphql/:

GraphiQL Playground

To avoid making this article very extensive I’ll include a screen record video of the API:

And with that, I “close” this article. Hope everyone enjoys it and I would like to hear from you.

PlainEnglish.io 🚀

Thank you for being a part of the In Plain English community! Before you go:

GraphQL
Graphene
Python
Django
API
Recommended from ReadMedium