Django Graphql

Posted : admin On 1/26/2022
  1. Django Graphql Auth
  2. Django Graphql

I recently stumbled my way though integrating Django with Ariadne and am going to share the lessons learned here. We'll cover the following topics:

  • Setting up Django with Ariadne
  • Hooking up resolvers to our Django models
  • Modularizing our schema and resolvers
  • Writing tests
  • Dates, and Datetimes
  • Authentication
  • Accessing the User object
  • Django Vue.js and GraphQL - Step by step. Create Django project. Split Configuration into production and development. Create home page. Add Django Debug Toolbar. Add vue.js frontend. Integrate with the Django project. Add url for About page. Integrate Django with GraphQL. Integrate vue.js with graphql.
  • From django.urls import path from graphenedjango.views import GraphQLView urlpatterns = #. Path('graphql', GraphQLView.asview(graphiql=True))(Change graphiql=True to graphiql=False if you do not want to use the GraphiQL API browser.) Finally, define the schema location for Graphene in the settings.py file of your Django project.

Setting up Django with Ariadne

Django Graphql Auth

To start we need to install Django and Ariadne and create an empty Django project:

To get the GraphQL server working, there's only two things we need to do. First we need to modify the INSTALLED_APPS in our settings file.

Then we need to modify our urls file to include Ariadne's GraphQLView with a placeholder schema:

Now if you run ./manage.py runserver and paste localhost:8000/graphql into the browser, you'll see the graphql playground:

We can test our GraphQL operations the same way we'd test any other Django view. GraphQL operations are sent as POST requests to the /graphqlendpoint. The query/mutation is passed as a string in the JSON payload. As an example, here are tests for our. Deployment - Intro¶. Deploying a FastAPI application is relatively easy. There are several ways to do it depending on your specific use case and the tools that you use. You will see more details to have in mind and some of the techniques to do it in the next sections.

Hooking up resolvers to our Django models

Let's make our example more realistic by creating resolvers that actually interact with a Django model. To do this we're going to need to create a Django app and add a model in the app's models.py:

We'll start with two GraphQL operations: a query books and a mutation createBook. Let's modify our urls file with the new schema and resolvers:

Now if we visit the graphql playground again, we are able to create and list books:

Modularizing our schema and resolvers

Putting everything in our top-level urls file works fine for now, but this isn't going to scale. It would be better to move our schema into .graphql files that live in the Django apps they relate to. Secondly, we want to move our GraphQL config out of the top-level urls.py file and into a dedicated graphql_config.py. Let's start by moving our schema and resolvers related to book into the books app:


Our Query and Mutation types will live in a top-level schema file:

And our GraphQL config will be moved out of the 'urls.py' file into a dedicated 'graphql_config.py'.

Now our urls file can be simplified to look like this:

Writing tests

We can test our GraphQL operations the same way we'd test any other Django view. GraphQL operations are sent as POST requests to the /graphql endpoint. The query/mutation is passed as a string in the JSON payload. As an example, here are tests for our createBook mutation and our books query:

Converting between camel case and snake case

The JavaScript convention is to use camel case, while in python we use snake case. Ariadne provides a way to automatically convert between these two naming conventions. To make this work we have to tell Ariadne to use the snake_case_fallback_resolvers in our graphql config. This default resolver will map our resolver return values from snake case to camel case:

We'd also like to automatically convert our query/mutation arguments from camel case to snake case (i.e. the keyword arguments that get passed to our resolvers). For this Ariadne provides a decorator convert_kwargs_to_snake_case that we can wrap our resolvers with:

Let's demonstrate by adding a published_at field to our model and resolvers.


In our GraphQL schemas, we're going to use the camel case version publishedAt:


Dates and Datetimes

Ariadne provides scalar mappings between ISO formatted strings and python datetime/date objects. This allows us to avoid manually converting between strings and datetime objects, and makes sure that they are converted to a string format readable by common javascript libraries like moment.js. First, we need to add the DateTime and Date scalars to our schema:


Now, we need to tell Ariadne how to convert our scalars to and from python objects by including date_scalar and datetime_scalar in our schema:

Authorization

If you are using GraphQL as the backend server for a web app like me, then you probably only want users who are logged in to be able to use the /graphql endpoint. The easiest way to do this is to wrap the GraphQL view with Django's @login_required decorator.

The login_required decorator will attempt redirect the use to the login page with a 302 if they aren't authenticated. Apollo client won't follow the redirect by default, so this is something you'll have to configure client side.

Django graphql subscriptions

Accessing the User object

Ariadne provides access to the user object through the second positional argument, the 'info' object, in each resolver:

We can modify our list_books resolver to only return books associated with the authenticated user like this:

In a normal HTTP request, Django's AuthenticationMiddleware puts the user on the request object. Since we're using graphql over HTTP, each graphql operation is carried in an HTTP request that passes through all the same middleware. That's how the user object gets populated.

Closing remarks

I hope this was helpful :)

GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. It was developed internally by Facebook in 2012 before being publicly released in 2015. It allows clients to define the structure of the data required, and the same structure of the data is returned from the server, therefore preventing unnecessary data from being returned.

GraphQL has three primary operations: Queries for reading data, Mutations for writing data, and Subscriptions for automatically receiving real-time data updates. A GraphQL server provides clients with a predefined schema – a model of the data that can be requested. The schema serves as common ground between the client and the server.

In this tutorial we will use Graphene, a GraphQL framework for Python, to build a Django API that uses queries and mutations.

Tutorial Requirements

To follow along with this tutorial you should have the following items:

  • Python 3.6 or newer.
  • Virtualenv, to create a virtual environment for the tutorial project.
  • Postman, to send requests to our API.
  • A working knowledge of the Django web framework.

Project setup

We will begin by creating a virtual environment and installing necessary Python packages.

Create a folder for our project:

Then create a Python virtual environment and activate it. If you are following this tutorial on Windows:

If you are using a Mac OS or Unix computer:

Install the dependencies required for our project:

Create a new django project:

Change your current directory to the project:

Create a api app in the books_api project

Next register the api app and integrate the graphene-django third-party app we installed earlier into our books_api project. Find the INSTALLED_APPS list In books_api/settings.py and add api and `graphene-django’ at the end:

While in books_api/settings.py, go to the bottom of the file and add a GRAPHENE dictionary with settings for the graphene-django package:

The SCHEMA setting tells Graphene where to find the GraphQL schema for the application. We’ll define the schema after we have the database created.

Database model

Open the api/models.py file and type in the code below to add the Book database model:

Then create and run the migrations for our database:

To help in testing this project we can now populate our database with some data. To do this, you create a data.json file in the project directory where the manage.py file is, and copy the following data into it:

With the data.json file saved to the current directory, run the command below to import the data into the database:

Django Graphql

Next, add the GraphQL endpoint at the end of the urlpatterns dictionary in file books_api/urls.py:

Building a Books API with GraphQL

In this section we will be building an API with Graphene using GraphQL queries and mutations.

Implementing a GraphQL Schema

Create a new file in the api/schema.py folder:

In this step we have created two classes, The first one is BookType, which adapts the Book model to a DjangoObjectType. We set fields to __all__ to indicate that we want all the fields in the model available in our API.

The Query class defines the GraphQL queries that the API will provide to clients. The all_books query will return a list of all the BookType instances, while the book query will return one BookType instance, given by an integer ID. The class defines two methods, which are the query “resolvers”. Every query in the schema maps to a resolver method.

The two query resolvers query the database using the Django model to execute the query and return the results.

Adding data updates with GraphQL mutations

We will now add create, update and delete operations through mutations. While still in the api/schema.py file, add the code below at the bottom:

The BookInput class defines fields similar to our Book model object to allow the client to add or change the data through the API. We will use this class as an argument for our mutation classes.

Let’s add a mutation to create new books. Add the following code at the bottom of api/schema.py:

The CreateBook class will be used to create and save new Book entries to the database. For every mutation class we must have an Arguments inner class and a mutate() class method.

We defined an instance of the BookInput class we created earlier as our arguments, and we made it mandatory with the required=True option. After that we defined the model we are working with by doing this book = graphene.Field(BookType).

In the mutate method we are saving a new book by calling the save() method on a new Book instance created from the book_data values passed as argument.

Below you can see the implementation of the UpdateBook mutation. Add this code at the bottom of api/schema.py:

Django graphql react

The UpdateBook mutation class is very similar to CreateBook. The difference here is the logic in the mutate() method, which retrieves a particular book object from the database by the book ID provided and then applies the changes from the input argument to it.

Finally, let’s add a delete mutation. Add the code that follows at the bottom of api/schema.py:

In the DeleteBook mutation class we have graphene.ID as the only argument. The mutate() method uses this id to remove the referenced book from the database.

We now have two queries and three mutations defined. To register these with Graphene, add the code below at the end of api/schema.py:

Testing the GraphQL API

Django

We are not ready to test the API. Let’s start the Django server:

Now visit http://127.0.0.1:8000/graphql in your browser. You should see the GraphIQL interface for interactive testing of the GraphQL API.

The black arrow in the diagram above is where you input your GraphQL code. Then you click on the play button in the top left corner of the screen to run the code and get a result in the area indicated with the blue arrow.

Issuing a query

Queries are used to request data from the server. The GraphQL code below is requesting all the books from the database. Enter it in the left-side panel of the GraphIQL interface.

Press the play button to execute the query and see the results in the right-side panel.

Next try the following query, which requests a single book by its id:

Note how each query can specify which of the attributes of the book model need to be returned.

Creating a book

The following GraphQL snippet defines a mutation that adds a new book to the database:

Updating an existing book

The next GraphQL mutation updates the book with id=6:

Deleting a book

The final mutation example deletes the book with id=6 from the database:

Testing the Book API with other GraphQL clients

Django CSRF prevents unauthenticated users on the website from performing malicious attacks. Given this, any POST request made from an external application outside the Django site will result in a 403 Forbidden Error.

To avoid this there are two options. The most secure option is to add the CSRF token generated by the Django application to the POST requests that your client makes to the GraphQL endpoint. See the Ajax section in the Django documentation to learn about this option.

An easier, but less secure option is to exempt the GraphQL endpoint from CSRF protection. To do that, open theapi/urls.py file and change the definition of the GraphQL endpoint as follows:

The csrf_exempt wrapper added to the GraphQLView removes the CSRF token verification from the endpoint.

If you want to make sure the CSRF protection does not interfere with your GraphQL endpoint, you can use Postman to send GraphQL requests to the Django API:

Using the above screenshot as a reference, follow these steps to send a GraphQL request with Postman:

  • Paste your GraphQL endpoint http://127.0.0.1:8000/graphql in the box with the purple arrow.
  • Click on the first white arrow pointing to the “Body” option
  • Click on the GraphQL options at the second white arrow
  • Paste your query code in the query box and click on the “Send” blue button.
  • You will see the result of your API request at the bottom, in the light green arrow area.
  • Notice the blue arrow area, where you should be making a GET request for queries, or a POST request for mutations.

Try the code snippets we used above to test our API through Postman.

Conclusion

In this tutorial we have created a simple GraphQL API in Django using the Graphene-Django package built on top of Graphene, which made it easy to add GraphQL functionality to our Django application.

We created queries to read data, mutations to write and change data and tested our API using the GraphIQL interface provided by the Graphene-Django library and the popular API client Postman. You can find the complete code for the project here.

Adeyemi Atoyegbe is a self-taught Python developer. You can find him on Twitter, GitHub.