An Intro to GraphQL API

An Intro to GraphQL API

Today, I want to show you how to build serverless backends with the Hasura GraphQL API. After looking at GraphQL and its advantages, we will learn how to create new tables for our API. Next, we want to fill our database with real data. Of course, we want to have relationships between our tables. Finally, we will learn how to manipulate the data using mutations. No previous knowledge of GraphQL is required to follow this tutorial.

Today, I want to show you how to build serverless backends with the Hasura GraphQL API. After looking at GraphQL and its advantages, we will learn how to create new tables for our API. Next, we want to fill our database with real data. Of course, we want to have relationships between our tables. Finally, we will learn how to manipulate the data using mutations. No previous knowledge of GraphQL is required to follow this tutorial.

Table of Contents

  • About GraphQL
  • About Hasura
  • Creating a project
  • Create tables
  • Insert data
  • Queries
  • Relationships
  • Object relationship
  • Array relationship
  • Many-to-many relationship
  • Mutations

About GraphQL

GraphQL is a typed query language for APIs. More and more tech companies, including tech giants like Facebook, Twitter and GitHub, are switching from common REST apis to GraphQL solutions. The main advantages of GraphQL over other API architectures like REST are:

  • About GraphQL
  • About Hasura
  • Creating a project
  • Create tables
  • Insert data
  • Queries
  • Relationships
  • Object relationship
  • Array relationship
  • Many-to-many relationship
  • Mutations

Here is a sample query:

And its corresponding result:

As you can see, the query is very intuitive and the result is predictable. You get exactly what you ask for: not more and not less.

As web applications tend to get more complex, there is a growing need for fast and easily maintainable solutions. So this is probably a good time to have a glimpse at GraphQL. But how do we use it? Do I need to build my own server? How can we connect it to our frontend? Don’t worry, we’ll get there.

About Hasura

Hasura provides you with an open source GraphQL engine that runs in a Docker container. Hasura connects to the Postgres database that is created with the project. You can also run Hasura GraphQL on top of an existing project. This can in particular be useful if you want to migrate to GraphQL, as it allows you to do the migration in smaller steps.

There are several options as to where you can deploy your GraphQL API: Heroku, Docker, Digital Ocean, Azure, AWS and Google Cloud.

Creating a project

In this post, we will get started with Heroku. We are going to create a Harry Potter api 🤓

https://dashboard.heroku.com/new?button-url=https%3A%2F%2Fdocs.hasura.io%2F1.0%2Fgraphql%2Fmanual%2Fgetting-started%2Fheroku-simple.html&template=https%3A%2F%2Fgithub.com%2Fhasura%2Fgraphql-engine-heroku

On the dashboard, choose a (unique) name for your api and click the “Deploy” button:

That was easy, right? Now, if you scroll to the bottom you will see this:

When you click on “View”, the Hasura console will open in the GraphiQL tool, which is also one of the features that makes your life with GraphQL super easy. In the Hasura console, you can create tables and test queries. Let’s have a quick look at the console:

  1. This is the (only) endpoint used to interact with the api. When we later poll data from external services, this is the URL we need to access. And yes, you’ve seen correctly: requests to GraphQL are always POST requests.
  2. Here, you can add request headers. If you want to add authentication (e.g. with JWT tokens) later, you can add the headers here.
  3. This is the field where you can test queries.
  4. Here, the results will be displayed.
  5. We will go there next, to create our first table.

Create tables

We first want to create a table to store movies. Let’s do that!

  1. This is the (only) endpoint used to interact with the api. When we later poll data from external services, this is the URL we need to access. And yes, you’ve seen correctly: requests to GraphQL are always POST requests.
  2. Here, you can add request headers. If you want to add authentication (e.g. with JWT tokens) later, you can add the headers here.
  3. This is the field where you can test queries.
  4. Here, the results will be displayed.
  5. We will go there next, to create our first table.

Create the following two tables:

characters (id: UUID, name: Text, hair_color: Text, house: Text, wizard: Boolean, birth_year: Integer, patronus: Text)

actors (id: UUID, name: Text, birth_year: Integer, awards: Integer)

Insert data

Let’s add some data data:

Add one other character, as well as two movies and two actors.

Queries

Now that we have some data, we can make our first query in GraphiQL.

It will return the two characters that we have already inserted into our characters table.

There are a lot of different constraints you can add to your queries. For example, you can make sure only to get a certain number of objects. Or only get the objects where a certain condition is true. All this is very well documented by Hasura: https://docs.hasura.io/1.0/graphql/manual/queries/simple-object-queries.html. You can read through it and tweak your queries, so that they return different results. You might have to add some more data in order to do so.

Relationships

Currently, we have three tables that are all independent from each other. With a query, we can retrieve movies, characters and actors. But we cannot retrieve the movies with their characters and in turn the respective actors. In order to do this, we need to define relationships.

There are two different types of relationships: the object relationship and the array relationship. The object relationship is a one-to-one relationship. For example, a character has a single nested resource that is called actor. The array relationship is a one-to-many relationship. For example, a movie will have an array of nested resources called scenes.

Object relationship

Let’s first model the relationship between characters and actors. The first step is to add a actor_id to the characters table:

After adding the column, we need to edit it and to make sure that the actor_id is actually a foreign key, pointing to the actors table.

When we go to the tab “Relationships” on characters, a suggested relationship will appear. That’s right — Hasura detects foreign keys automatically and makes suggestions regarding relationships. As a name, we’ll take “actor”.

Next, we want to connect the characters with the corresponding actors in our database. When we now look into the characters table, we can see that the actor_id for the previously created characters is NULL. We can now edit the data and add the ids of the actors that correspond to these characters.

Now the characters and their actors are linked. Now we can access fields from the actors along with the characters in the same query:

Array relationship

The array relationship is a one-to-many relationship. This means that one object of a table can have several objects of another table. Let’s say in our example, one movie can have several scenes and each scene belongs to one movie. A scene has an id, a name, a location and a movie_id. So let’s create a new table called “scenes” to our database:

Great! Now, just like we did before, we need to modify the table and make the movie_id a foreign key:

When we now go to the movies table and click on “Relationships”, we can see the suggested array relationship for scenes. Let’s add this relationship and call it “scenes”. This is all that is necessary to create an array relationship. To test it, insert some rows into the scenes table.

Many-to-many relationship

As explained before, the array relationship is a one-to-many relationship. However, in our case of movies and characters, we have a many-to-many relationship. One movie can have several characters and one character can appear in several movies. For this scenario, we need to create a join table that we will call “movie_characters” in which we can store the relationship between one movie and one character. Let’s create the “movie_characters” table that has an ID, a movie_id and a character_id.

From the perspective of the movie_characters table, we need object relationships to both the movies table and the characters table. This is because in each movie_character, there is one movie and one character stored.

Like above, edit both the movie_id and the character_id on the movie_character table and tick the checkbox for them to be foreign keys. Then add the correct reference table and the reference column. For the movie_id, the reference table is movies and for the character_id, the reference table is characters. For both reference columns, it will be ID.

When you now click the tab “Relationships”, you’ll see two suggestions for object relationships. Add them both and call them “movie” and “character”. Once added, it should look like this:

Of course, like above, we need to create the relationships with our data. Create new rows in the movie_characters table for each movie — character relationship, using their IDs.

Yayy, now all our tables are modelled with their correct relationships. Let’s test it with a query.

Isn’t this neat? With just one query, we are able to access several resources with those fields we want. Compared to REST where usually the whole object is returned, we can reduce the query to the essentials. This makes the API more efficient, more lightweight and easier to handle.

Mutations

So far, we learned how to get data from our API. But what about adding new data? In our case, we might want to add a movie or a character. For this, we need mutations. Mutations are easy to use with the GraphQL API and just like queries, we can try them in the Hasura console:

Let me explain what is happening here. Inside a mutation, we can call different methods like insert, update or delete on the resources that we store in our database. In our case, we want to insert a new movie. We need to pass the movies as objects and it is possible to insert several objects in one mutation. In the end, we need to return something, which is the ID of the newly created object in our example.

Again, there is full documentation on mutations on the Hasura website: https://docs.hasura.io/1.0/graphql/manual/mutations/index.html. Go through the examples and try some other mutations, like deleting a movie.

That is it for now. I hope you had fun learning about GraphQL and that you are eager to extend your Harry Potter API with lots of new tables and data. If something is not clear, you can always send me an email at [email protected] or message me over Twitter: https://twitter.com/rubydwarf.

Stay tuned for updates. I will soon publish another blogpost on how to connect your Hasura backend to your VueJS frontend 🎉

Explore GraphQL with Apollo & React: Build a Superhero Database

Explore GraphQL with Apollo & React: Build a Superhero Database

In this article, We share some light on what GraphQL is and give you an opportunity for some hands-on experience with Apollo and React.

In this article, We share some light on what GraphQL is and give you an opportunity for some hands-on experience with Apollo and React.

Curious about all the buzz surrounding GraphQL, but not quite sure why you should be excited? You’re in the right place! We’ll shed some light on what GraphQL is and give you an opportunity for some hands-on experience.

Let’s start by clearing the air and answering the $20,000 question: what is GraphQL? No, it’s not an obscure function on your TI-89. It’s a query language at heart — or query specification more accurately — that can be used to fetch data from just about any data source.

Better yet, it allows you to fetch the exact data you need — no more, no less — in a single network request. While that may not sound like the sexiest tech to come out of the Facebook factory of innovation, you may just find yourself pleasantly surprised at how useful it can be.

All that’s needed is an Apollo server to act as our endpoint and a React app using the Apollo client to leverage any data within. We’ll tackle the server first.

Getting Started with Apollo Server

To get our Apollo server started, create a folder called apollo-server in your favorite working directory. Next, enter that directory and run the following npm command — you do have npm and Node installed, right? — to get the Apollo framework in place:

npm install apollo-server apollo-server-express graphql

Now that you’ve got the various bits and pieces of the Apollo server in place, it’s time to actually tell our server what to serve. Go ahead and create an empty index.js file in the apollo-server directory and add the following to it:

const { ApolloServer, gql } = require('apollo-server');

This line simply pulls in the required objects for starting an Apollo server and parsing our query strings into query documents for GraphQL.

Our First GraphQL Schema

Next up, let’s add our first schema:

// This will be our GraphQL schema
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    superpowers: [Superpower]!
  }

  type Superpower {
    id: ID!
    text: String
  }

  type Query {
    users: [User]
    user(id: ID!): User
  }
`;

Here we add our type definitions. The first is of type User which we define as an object having an id, name, and superpowers field. The second is a simple id and text to describe each superpower. Finally, the third defines two acceptable queries — users and user — that, respectively, return all users or a single user that matches the provided id argument.

Pretty easy, right?

Adding a Dash of Data

Next, let’s add some mock data to bring our schema to life:

// This will be our mock data to query
const users = [{
  id: '1',
  name: 'Peter Parker',
  superpowers: [{
    id: '1',
    text: 'Web slinging'
  },{
    id: '2',
    text: 'Spidey sense'
  }]
},{
  id: '2',
  name: 'Tony Stark',
  superpowers: [{
    id: '3',
    text: 'Industrial design'
  },{
    id: '4',
    text: 'Robotic fashion'
  }]
}];

All we’re doing here is adding two users to our mock data. It’s worth pointing out that GraphQL isn’t relegated to only querying JavaScript arrays. This could be any database or other data construct. We’re just keeping things simple here to focus on the task at hand.

Don’t Forget Resolvers

Next up, we need to tell GraphQL how to interpret the queries we defined above. This is done with resolvers:

// This will be a map of functions to return the data described by our schema
const resolvers = {
  Query: {
    users: () => {
      return users
    },
    user: (root, { id }) => {
      return users.find(user => user.id === id);
    },
  },
};

You’ll notice the first query users requires no arguments and returns the entire users list (at least in theory, more on that later). The second query user accepts the ID of the user to be fetched and returns said user.

Putting It All Together

To finish off our Apollo server, we just need to instantiate a new instance and start listening for connections:

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({ url }) => {
  console.log(`Apollo server started at ${url}`)
});

Here we send the ApolloServer constructor our schema and resolvers created above. All that’s needed then is to actually start the server, but first, here’s what your index.js should look like:

const { ApolloServer, gql } = require('apollo-server');

// This will be our GraphQL schema
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    superpowers: [Superpower]!
  }

  type Superpower {
    id: ID!
    text: String
  }

  type Query {
    users: [User]
    user(id: ID!): User
  }
`;

// This will be our mock data to query
const users = [{
  id: '1',
  name: 'Peter Parker',
  superpowers: [{
    id: '1',
    text: 'Web slinging'
  },{
    id: '2',
    text: 'Spidey sense'
  }]
},{
  id: '2',
  name: 'Tony Stark',
  superpowers: [{
    id: '3',
    text: 'Industrial design'
  },{
    id: '4',
    text: 'Robotic fashion'
  }]
}];

// This will be a map of functions to return the data described by our schema
const resolvers = {
  Query: {
    users: () => {
      return users
    },
    user: (root, { id }) => {
      return users.find(user => user.id === id);
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({ url }) => {
  console.log(`Apollo server started at ${url}`)
});

Go ahead and fire it up with node index.js and visit http://localhost:4000/ to see the fruit of your labor!

You should be greeted with a GraphQL playground that lets you try out interactive queries against the schema you’ve created.

Going Hands-on

Let’s test it out by entering this query in the left-hand pane:

query {
  user(id: 1) {
    name
  }
}

Here we use the user query we just set up, and pass it the id of 1. We’re also telling GraphQL that we only want to return the name of said user. The result in the left hand pane — after clicking the play-like button — should look like this:

{
  "data": {
    "user": {
      "name": "Peter Parker"
    }
  }
}

Let’s say you want to take a peek at his superpowers too. All you have to do is request that field:

query {
  user(id: 1) {
    name,
    superpowers {
      text
    }
  }
}

We added the superpowers field and, since we only care about the text and not the superpower ID, we specify as much. The result should now display each superpower for our first user:

{
  "data": {
    "user": {
      "name": "Peter Parker",
      "superpowers": [
        {
          "text": "Web slinging"
        },
        {
          "text": "Spidey sense"
        }
      ]
    }
  }
}

Say we want to grab all users and their superpowers, we can rely on the users query we defined:

query {
  users {
    id,
    name,
    superpowers {
      text
    }
  }
}

And the result:

{
  "data": {
    "users": [
      {
        "id": "1",
        "name": "Peter Parker",
        "superpowers": [
          {
            "text": "Web slinging"
          },
          {
            "text": "Spidey sense"
          }
        ]
      },
      {
        "id": "2",
        "name": "Tony Stark",
        "superpowers": [
          {
            "text": "Industrial design"
          },
          {
            "text": "Robotic fashion"
          }
        ]
      }
    ]
  }
}

Only care about superpowers? We can do that too:

query {
  users {
    superpowers {
      text
    }
  }
}

And you get:

{
  "data": {
    "users": [
      {
        "superpowers": [
          {
            "text": "Web slinging"
          },
          {
            "text": "Spidey sense"
          }
        ]
      },
      {
        "superpowers": [
          {
            "text": "Industrial design"
          },
          {
            "text": "Robotic fashion"
          }
        ]
      }
    ]
  }
}

At this point you should be able to appreciate the supreme flexibility and allure of GraphQL. With a single query and connection we can retrieve any slice of the data we desire. All that’s necessary is a well designed schema and the resolvers to support it.

Even better, back-end developers and front-end developers can do their thing almost independently. With the schema acting as a middle man, both groups can effectively avoid stepping on each other’s toes. And really, that’s GraphQL in a nutshell. Before we wrap this tutorial up however, let’s take a look at how to integrate these queries with an actual React app.

Introducing React to the Mix

Go back to your root working directory and run the following commands to set up a bootstrapped React app with the requisite GraphQL and Apollo libraries:

npm install -g create-react-app
create-react-app my-graphql
cd my-graphql
npm install apollo-boost react-apollo graphql

Next, replace the contents of src/index.js with the following:

index.js:

import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'

import App from './App'

const client = new ApolloClient({
    link: new HttpLink({ uri: 'http://localhost:4000/graphql' }),
    cache: new InMemoryCache()
})

ReactDOM.render(
    <ApolloProvider client={client}>
    <App />
    </ApolloProvider>,
    document.getElementById('root')
)

All we need here are the usual imports for a React app along with the Apollo client to interface with our new Apollo server. To create the Apollo client we just need a link to the server http://localhost:4000/graphql and a way to cache our goods. With that, we simply render the app.

Next, we need to set up the app to query and display the data presented by our Apollo server. Go ahead and replace the default src/App.js with this:

App.js:

import React from 'react'
import { Query } from 'react-apollo'
import { gql } from 'apollo-boost'

const TEST_QUERY = gql`
  {
    user(id: 1) {
      id,
      name,
      superpowers {
        text
      }

  }}
`;

const App = () => (
  <Query query={TEST_QUERY}>
  {({ data: { user }, loading }) => {
      if (loading || !user) {
        return <div>Loading ...</div>;
      }
      return (
    <p>
        {user.name} ({user.id}) has the following superpowers:
        <ul>
        {user.superpowers.map(superpower => (
            <li>
                {superpower.text}
            </li>
        ))}
        </ul>
    </p>
      );
    }}
  </Query>
);

export default App

You should see some familiar patterns here. We first use gql to create a GraphQL query document that requests the user with ID 1 — more specifically, their ID, name and superpowers text. Then we pass the document to our server with the Query tag. It’s here that we can format the results in a pretty React app.

Go ahead and start the server with npm start and check out the beautiful results at http://localhost:3000/.

And with that, our tutorial is complete. You’ve created an Apollo server and fed it some simple data structures. You discovered how to write schemas and resolvers to define interactions with the data. You then practiced querying specific pieces of that data. Finally, you tied it all together with a React app that retrieves data from the server and presents it in a nicely formatted way.

While this should be enough to get you started with integrating GraphQL in your future projects, there’s lots still to learn. Mutations for adding and changing data is a great next step.

Curious Use Cases of GraphQL (and The Future of GraphQL)

Curious Use Cases of GraphQL (and The Future of GraphQL)

In this GraphQL tutorial, we’ll show how developers are using GraphQL as an API gateway to accomplish things that you may have never thought possible. Curious Use Cases of GraphQL (and The Future of GraphQL). As GraphQL moves into the mainstream, the tooling & ecosystem has grown and has made it possible to do much more with GraphQL than using it as just a data layer.

As GraphQL moves into the mainstream, the tooling & ecosystem has grown and has made it possible to do much more with GraphQL than using it as just a data layer. In this talk, I’ll show how developers are using GraphQL as an API gateway to accomplish things that you may have never thought possible.

More details:

When we think of GraphQL at the resolver level, we typically associate some type of database as the resolver data source, but in practice a resolver is simply a function. What this means is that we can do much more with our GraphQL APIs & our resolvers than we ever thought possible, including things like taking existing REST APIs & transforming them into GraphQL APIs (http resolvers), passing the query to Lambda or serverless functions for processing & returning the response via a GraphQL query (for things like AI & ML), geospatial & time-based queries (passing the query to Elasticsearch), & even VR & AR apps (passing in user location / app info & using the subscription to transmit image assets). In this talk, I’ll walk through what this looks like in theory & in practice, demoing 4 different applications that implement this functionality & showing the code that make the magic happen.

GraphQL and Django Tutorial: Should you be using Django with GraphQL?

GraphQL and Django Tutorial: Should you be using Django with GraphQL?

Should you be using Django with GraphQL? Do you need GraphQL with Django? Check GraphQL and Django tutorial to find out how the language can improve your development experience.

For the past 5 years, Django has been the most effective framework for making quick web applications, API Endpoints, or Admin panels for other applications.

One of the biggest advantages of Django is its ability to enable users to write less code and get started quicker, especially if you’re including an admin panel and a fully-manageable database migration process as base functionality.

Django Rest Framework—an external toolkit—makes it easy to build API endpoints. It basically wraps full CRUD API around the Django Model with just a few lines of code.

This means that building any basic CRUD API with Django helps to keep more of a development focus on UI parts, which are key elements of all software products.

Similarly, GraphQL aims to automate backend APIs by providing type strict query language and a single API Endpoint where you can query all information that you need from UI and trigger actions (mutations) to send data to the backend.

My journey with GraphQL started with Facebook’s API, where GraphQL comes from.

Naturally, GraphQL is considered to be very close to the JavaScript world, mostly because browser-based apps are the first adopters of that technology.

That’s why my first GraphQL server+client was done in Node.js and React.js. After having the first app built on top of GraphQL API, I started to use it exclusively for my Web-based projects.

Advantages of GraphQL

As you may have guessed, there is a library for Django to support GraphQL called Graphene Django, which is very similar to the Django Rest Framework.

However, there are significant differences between Django Rest and Django with GraphQL.

The key difference lies in UI usability: with Rest API, you’re getting endless URLs with specific parameter names where you have to check types and specific values.

Meanwhile, with GraphQL you’re defining mutation similar to the code below and getting strictly defined variable names and types, which become part of an automatic GraphQL type validation.

type Mutation {
  userLogin(email: String!, password: String!): UserLoginResponse
}

type UserLoginResponse {
  token: String
  error: Boolean
  message: String
}

GraphQL also comes with another bonus packaged inside its type system. It automatically generates documentation where you can get available queries and mutations with their parameters/return types.

Django Rest also generates some form of documentation, but it is not as usable as the GraphQL Playground displayed below.


If you think this type of interface is available for all kinds of GraphQL endpoints, you’re wrong — this is only available in development mode servers.

In terms of security, having one API Endpoint is naturally more manageable than having hundreds of them—especially when you consider the fact that GraphQL automatically keeps specific type rules and won’t allow requests with incorrect parameter names or values.

Django ❤️ GraphQL

Let’s make a basic setup with Django and GraphQL just to demonstrate how powerful this setup can be. On one hand, you’re getting easy CRUD management with database. On the other hand, you’re getting a very powerful API query language with a single endpoint.

Installation should be very easy. Just follow the steps defined here

The interesting parts are defining GraphQL types and queries in Python. It’s actually based on your database models, but you can also define custom queries without using Django Models.

# schema.py
from graphene_django import DjangoObjectType
import graphene
from .models import Post as PostModel
from .models import User as UserModel

class Post(DjangoObjectType):
    class Meta:
        model = PostModel
        interfaces = (relay.Node,)

    @classmethod
    def get_node(cls, info, id):
        return Post.objects.get(id=id)

class User(DjangoObjectType):
    class Meta:
        model = UserModel
        interfaces = (relay.Node,)

        posts = graphene.List(Post)

    def resolve_users(self, info):
                return Post.objects.filter(user=self)

    @classmethod
    def get_node(cls, info, id):
        return User.objects.get(id=id)

class Query(graphene.ObjectType):
    users = graphene.List(User)

    def resolve_users(self, info):
        return UserModel.objects.all()

schema = graphene.Schema(query=Query)

Now you can very easily query all users with their posts.

The most important thing to remember is that you can query fields you want, which will affect the overall load time and traffic usage on the UI side.

For larger user bases, it’s important to keep traffic low and only query the fields you need. In the case of Rest API, you will get all fields anyway.

query {
  users {
    name
    posts {
      id
    title
    content
    }
  }
}

This is the basic query outcome from the Python definition, which is pretty simple and — compared to Rest API — more expressive than you may think.

What about GraphQL Subscriptions?

GraphQL Subscriptions function as a way to tell the server to retrieve data based on a specific query whenever the data is available.

It all works with WebSockets in near-real time, which means we have to somehow include Django Websockets and configure our backend server for accepting WebSockets.

Basically, GraphQL is just an API query language interpretation that works with any kind of network transportation when handling client and server-side GraphQL language interpretation.

It may seem difficult at first, but there’s an open-source library and Django GraphQL Subscriptions over at the Django Websockets module.

# settings.py

GRAPHENE = {
    'SCHEMA_INDENT': 4,
    'MIDDLEWARE': [
        # Others middlewares
        'graphene_django_subscriptions.depromise_subscription',
    ]
}

This will be enough to handle the subscription schema later on as a Subscription query.
A quick aside: Pinterist actually works entirely on GraphQL Subscriptions, which is all built on top of Django Backend (but probably modified a lot.)

Conclusion

In my opinion, Django with GraphQL is more powerful and extensible than Django with Rest API.

However, it isn’t battle-tested and large companies are still in the process of adopting this kind of combination, but based on what you can get out of this simple configuration, imagine how much more comfortable web development will be when you use Django with GraphQL with modern technologies.