Adding a GraphQL API to Wagtail - Patrick Arminio
Published March 30, 2022
This video features Patrick Arminio at DjangoCon US 2018 in San Diego, California, USA.
DjangoCon US 2018 - Introduction to Django and GraphQL by Patrick Arminio
GraphQL has grown a lot overtime, but it seems to still be a new “thing” in the Python and Django World. This talk will be an introduction to GraphQL, explaining why it has been created and how you can use it in Python and Django.
Short speaker introduction
Small digression on how the “old” web used to be and how it has now evolved into the modern web
Really quick explanation of REST (just to make sure everyone is familiar with it)
What are some limitations of REST? What can we do about it?
Introduction to GraphQL, what it is, how’s using it and when has it been created?
GraphQL: query language syntax
GraphQL: types and introspection
GraphQL: operation, how to read data,update data and more
How to use Graphql with Python and Django
Let’s make a simple API
How to create queries
How to create mutations
Things to consider (security caching and performance)
Closing thoughts
This talk was presented at: https://2018.djangocon.us/talk/introduction-to-django-and-graphql/
LINKS:
Follow Patrick Arminio 👇
On Twitter: https://twitter.com/patrick91
Official homepage: https://patrick.wtf
Follow DjangCon US 👇
https://twitter.com/djangocon
Follow DEFNA 👇
https://twitter.com/defnado
https://www.defna.org/
GraphQL lets clients request exactly the data they need through a single typed endpoint, avoiding REST’s common overfetching, underfetching, and proliferation of custom endpoints. Patrick Arminio shows how to build GraphQL APIs with Django and Graphene, including object types from Django models, queries, mutations, introspection, and an early integration with Django Channels for subscriptions. He also covers authentication, field-level permissions, query-depth and cost limits, timeouts, static queries, and caching concerns, arguing that GraphQL can improve both developer workflow and client performance while noting that Python’s Graphene ecosystem still needs work.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: So hi everyone. My name is Patrick. I'm currently HR person at Python Italy and I currently live in London and I'm interested in both back-end and front end. I've been using Django for about 10 years now and doing frontend for about more or less the same time. And you can find me at Spartan9 online if you want to tweet me or if you have any question. Today I'm gonna talk about a technology that I've been using. over the past two years I think more or less. And one of the reasons why I try to experiment with technologies because I really want to improve my my workflow. I want to try to find new technology that can speed up my developer experience and also improve the user experience for the user of my the apps I build or the website I do So before digging into uh
Speaker 1: what GraphQL is, I'm gonna do like a small digression on the how the web used to be um what the web is now. So it used to be like something like um A simple collection of documents where you had a single server and you had like a list of documents where the user could navigate between them using links. And usually these documents were just HTML, CSS, and maybe some JavaScript for like some animation. But over time the web has has changed as we all know and the other requirements have have changed as well. So for example, we could have something like different data sources and one single backend that would handle this data and then send the data to all these clients that we can have like smartwatches, phones, um desktop devices and you will free just
Speaker 1: in night. these days. Um so one of the ways we used to communicate between a client and a backend we used to use APIs and more specifically using RAS APIs. If you're not familiar with REST API, it basically says that your API is a collection of resources and each resource has its own endpoint and you would do um Um use HCP verbs to do operation on those uh resources like get, post, delete, and patch. Um the problem is that REST is not perfect. It's actually it's not a standard as well, so everyone is doing it a little bit differently. One of the issues that I usually had is that you have to do too many API calls if you don't fetch data. So let's suppose that we have this simple API that's returning a user
Speaker 1: data So let's say the returns a user with their name, a list of friends, an avatar. Um this is nice. We are using um links so we can fetch data for all the other users. The problem is if I'm building an application where I need to show all this data in one single screen. I need to do an additional two requests in this case. So one request for each each user. And this is a waste of bandwidth for the user and also it's not easy to To implement in the front end. So one solution would be to create another endpoint where you can do user with friends and then you get something like this where you have the friends expanded The problem is that you might need also the images of those users in another application, so you might end up doing more and more endpoints for
Speaker 1: all your different use cases. especially if you wanna do for example light version of uh your application. And this over time it gets really, really big. And for example Coursera at some point had like a thousand different REST endpoints that they had to maintain a doc document. And and I think I think we can um if we can oops no. Uh if we can uh reduce this number of endpoints that we have to document this better. Another issue is that we have uh too much data when we send uh information to the client. So for example, instead of building the API with different um endpoints, we could send just one single API where you return all the data. That's possible to have.
Speaker 1: The problem with this one is that if I'm building a screen that only needs, for example, the username, we're basically wasting bandwidth and CPU resources because we're sending data that's not needed to the client. So can we can we do better? We could extend REST. The problem, as I said, is not a standard. So everyone is doing things differently, which means that we need to document. or the NAC extension that we built, for example, we could do I don't know uh get parameter to expand some fields. We can use headers to say oh this is a client, a mobile client, so send images that are smaller and so on So for some of this reason GraphCal was created. GraphCal solves some of some of those uh issues quite qua in a
Speaker 1: pretty nice way. Um GraphQL was created by Facebook in about 2012 and it's been uh open source in 2015. So it's it's been used in production for for a bit and also it's been used by loads of companies they say like Twitter, GitHub, Coursera and so on. So GraphQL is a specification and it's defined as a query language for the APIs. Uh that means that basically we can send a a document to to our GraphQL API and then we get back a result result. So basically it's the client that is in charge of saying what what the data is needed for for their application. A difference with uh REST APIs is that you only have one single HCP endpoint, which
Speaker 1: usually is slash GraphQL, and you would send a post request with a document. saying oh this is the data I need. And a document would look something more or less like this. So in this case we are saying oh I need the user, their name, their email and their list of friends with the name And when we send this request, as soon as if we have data on the back end, we get something like this back, which is basically what we asked for. If we change the document, we can we basically are changing the response as well. Another interesting thing of GraphicQL is that you have types. So every field in your uh API is typed. You have two different types. One is uh One is scolars, which are basically like base types like integer, float, string, and so on. You can also define custom types if you need to define
Speaker 1: like date time and so on. And then you have object types, which are basically a collection of types. So you have different fields where you can either have another scolar type or another object type For example, in our previous uh API we can have a type of user, they have name, an email, and a list of friends, and then you have a type of friend which is a which only has a name. Another cool thing I think is the introspection. So every GraphQL API by default uh returns a schema. So basically you can get all the fields that you have on this uh in this API. This allows to use tools like Graphicode to basically introspect the API without actually having to read the code or remembering everything. And I'm gonna show you a quick demo of this later.
Speaker 1: For example, in this case we are getting the information about this API without having to read the documentation. So I only show you how to show you how to do queries. Of course, we want to do uh multiple operations. And in Graphical you have three main operations which are query mutations and substitute subscriptions. subscription. Queer allows you to get data from the back end. Mutation allows you to do any operation with side effects like creating data or sending emails. else. And then you have subscription, which uh allows you to subscribe to events on the server for for example when something changes. Um this is a document that you send to do a query and since uh query is like
Speaker 1: um It's a common operation. This is like the short version of uh doing a query. The actual syntax looks like this, which basically you have the first um token is the operation type then there is a operation name which is basically used only for debugging then you can have parameters and something interesting of this uh GraphQL is also that you can have parameters for like nested fields. So for example in this case you can limit the number of friends in the response. And then same for mutation, you have the type, name of the operation, and optional parameters. And substitution works the same. So syntax is quite simple and easy to use. So this is really nice.
Speaker 1: We can we can we can use a bit Python using this library called GraphenePython. And I think it's the only library available so far. for GraphQL. It's easy to install just to prep install graphene and then to create a small hello world you can create a class called query where you define the fields. And in this case we are just defining uh hello field, which is returning a string in this case. And then you need to specify the resolver function. Resolver functions are basically the uh methods that are being called when you request a field. So in this case when we request the hello field, the resolve hello is going to be called. And it's gonna return only high Django conference now. And also you can execute them directly, but usually you would have a like a a Django
Speaker 1: view or uh um like a HCP call to to execute this schema instead of executing indirectly. And yes, there is also an extension for Django. This allows to use all the Django features like forms and models and so on. It's easy to install need to add to the installer app so you can use the views and then you need to specify the path to the schema so the um the Django view is able to fetch the schema schema. You add the the view to the file to the URLs and you can also enable the enable the ID graphical. Um and then it's quite easy. You can basically use the models to create the graphical types without typing again the older fields that you have. And then in the resolver function you can just return
Speaker 1: a query set which is basically gonna be converted by graphene to uh graphical types. Um that was quite quick. Let's let's create a simple API and This is based on the the Django pools application more or less. Let's say that we have two two two models. One is pool, which is only a question, and then there is a choice which is linked to a pool. It's got a choice text and Number of roots. So the first thing we want to do is to create the object types, which are basically the types for GraphQL. Those types are gonna be shown in the in your API. So using jung object type and uh it's quite easy to create those types because it it's basically up to the this base class to create all these the the fields that are needed for the models.
Speaker 1: You can also um you can also extend add additional fields and additional resolvers if you need to Then the first query we can do is the to list all the pools and is the document that we can send to the backend to fetch all the pools will look something like this. So you we fetch the field called pool, then we fetch the question for this pool and then the choice set. And in Python will look something like this. So we have a query and the field is a list of pool types and then there is a resolver function that's returning all the pools from the database. Then we can do a query for a single post. As I said, in GraphQL we can pass arguments to each field.
Speaker 1: So in this case, for example, we want to fetch the pool with ID, ABC. And we can do it like this. And the rest is similar to the previous one. The only difference that the field name is pull singular and accept accept an argument In Python looks like this, we define a graphene field, and then we pass the list of arguments. In this case just ID, which is a typo graphine. id and then in the resolver function we also get this parameter that we return a pool object Um then for for the mutation we can create one that allows you allows us to create a pool. So the The document that we can send looks like this. Basically it's like a function that accepts a question and a list of choices. And then we get back the the
Speaker 1: pull object. And in Python will look something like this. We need to extend the Graphene mutation, define the fields that this mutation is returning, and then the list of arguments. And then we need to create a mutation mutated function that it's basically if you use forms it's like the save in a in a Django form, then gets all the arguments and then you can create um the the pool duck. So let's quickly test it Okay. So I have this fine, it's not showing. Cool. Should be
Speaker 1: So I already have an instance of Django running with this backend code. And so let's say I want to fetch just a list of pools with the the the question text. I can easily do like this. So basically um every time I need to do like an API call, I can just send the document that I need with the structure I need back and I can can fetch it like this. And if you wanna get the choice set, you can just do something like this. And then I can back I can get back the list of choices for for this pool. There's also the ability to get like a single pool as I showed you.
Speaker 1: So in this case we are passing an argument uh with ID one and then we get the data for just that single um pool and if you wanna do if you wanna create a new a new pool we can use the mutation uh create pool Then but they are type also it's since everything is type the ID is telling me that there are some errors. So in this case it's telling me that I probably meant choices. And when I run this mutation, it's basically gonna create the uh pool on the back
Speaker 1: and it's also gonna return me return that to me, which is quite nice. Um Also like a quick demo I wanted to show you. Um uh there is support for uh Django channels, it's still not much of yet, but you basically can have um a subscription like this in this case. So basically every time a pool is updated the uh number of votes is gonna update in real time. So for I have a vote mutation where basically I can just uh send a vote to the to this pool. So every time I click this it's gonna update in both the pages. So the on the left side um basically we get the response from the back end, but on the right side we have a web socket connection
Speaker 1: uh running with Django channels that's receiving the updates in real time. So it's quite handy. The the only issue is I think I find that's still not measure yet. But hopefully soon we're gonna have um gonna have a nicer nicer way to to use Django channels with your fin but it can be done. So There's also integration with RAS framework and with uh Django forms. So basically you can reuse the forms that you have and the serializers that you have to create mutation. The problem that this I would say it's in beta. It's no i i it works but doesn't have all the features that we need. And I'm gonna be working on this during the sprints if you wanna help and see
Speaker 1: how actually works. So that that's cool. This is um it's really nice uh at least for my opinion. Problem is like it's a new technology especially especially in the Python world And there are some things that we need to keep in mind, especially with security. One of the most asked question on on GitHub and on SAC Overflow is how to do authentication. And there are three ways to do to do authentication. One is to use Django session and this works really well if you have uh an API that only works on uh your website so you don't have any mobile applications. Um the others the other way is to use headers like you do with a REST API so send like a token and the last one is to use parameters.
Speaker 1: So since you can add arguments to to all the fields that you have, you can for example send the token as an argument for a mutation. And this might work in some cases when you only have one mutation that needs authentication. So it's up to your requirements So another thing is permission. So like if you if you've been used to Django Ras framework, it's really easy to add permission to all the resources that you have. Unfortunately there is no builtkin features in Graphene yet But something nice I really want to work on is having permissions at on the field level. So for example, you can have an API where you have a user and And the email only it's only shown if the user is the current user or if
Speaker 1: a super user. user like git GitHub is doing something like that where they have a single graphical API that's being used also for like public access but also private access. And they have some fields are only available to uh the private API. But they only have one code base. Also it's really easy to build malicious queries because we are giving uh loads of power to the front end. So you can build something like this and imagine that this goes on on and on. So you basically can do a query that uh takes a lot of time and it's gonna it's easy to to someone to to dose your server I guess. Some strategies to to fix those those issues, for example, could be having timeouts.
Speaker 1: So you could say if a query takes more than one second, you can discard it because one second is already too much for for for a user and it might not terminate anyway. You can also do limits on the nesting which basically says oh if the if the user is requesting uh a field that's I don't know four levels deep. I'm not gonna do this query because it shouldn't be happening. They can also have uh a query cost. Basically you can add the score to each field and calculate the cost of query So if you have nested fields you can uh increment the cost um based on the number of uh of fields that you have. And this basically allows you to to say, oh I wanna only wanna run uh um query that are less expensive, I don't know, the
Speaker 1: fifty, which is a made up number. And you can also do static queries. It's something that uh there are a few few companies doing. I think Instagram is doing it. Basically Since they have control of the old pipeline, basically they can build a list of queries they're doing on the on their application and basically save it on the back end. in either in the database or on files. And basically the b the front end is gonna send, instead of sending a JSON document is gonna send an ID that corresponds to to a query. And this allows you to to also fix an issue that it's that we have with caching, which is basically we are doing post request and It's as you know, PostRequest is not easy to cache, so you need to either do the back-end cache or
Speaker 1: client cache. Um So with that said, I um one of the reason I want to give this talk is because I want to see more people using GraphQL in Python and also wanna see this library improve a lot because it's It's nice but it's not there yet. I think there is loads of room for infographic from this library. And also I think GraphQL is amazing using technology especially for like developers when you have to work with front-end people and um people working on I can different clients and also it's good for the user because we are not wasting the user bandwidth. Imagine if you have like a s like lower hand phone or if you have a connection that's really slow. You only send in the data that the client needs
Speaker 1: and it should be performant. So I'm gonna be uh at the sprints if you want to work on graphene. And thank you.
Speaker 2: Um so usually when you develop a library like that, uh you have like a problem that it solves. Can you kind of say in general what this solves?
Speaker 1: Oh yeah, so as I said solves most of the issues that we you have might have with REST API. So basically overfetching and underfetching of the data and also writing documentation. Uh in my experience when I built uh graphical API I said didn't really have to to write any documentation because the people working on the front end, we just read using the graphical IDE to to fetch the date the information about the API so I didn't really have to to explain to them but this this is the query that you need to do and also every time they had to do like a new um new screen on the application. I didn't have to build another endpoint because basically they can change the response that can get sent the to
Speaker 3: And how how does uh this look from the client side from from the JavaScript? How how does you usually create these queries that are
Speaker 1: so there are different ways you can go vanilla, so basically just some Sending an HTTP request with the it's it's basically it's a JSON uh with the query. Or you can use loads of there are a few frameworks. There is Apollo and Relay. Apollo is like the community one made by Uh it's I think now it's a company but it's like all open source and there there's also relay that's being made by Facebook. I I really u I use Apollo and m mainly because it works with different frameworks. You can use it with VR, Angular, V. js, and so on. But we can chat later if you want to have a look and how it works because it's another talk. Thank you.
GraphQL addresses REST’s tendency to require many endpoints and cause underfetching, while also avoiding overfetching by letting the client request exactly the fields it needs. Its schema and introspection can also reduce the need for separately maintained API documentation.
Discussed at 4:55GraphQL is a query language for APIs in which the client sends a document describing the data it needs and receives a correspondingly shaped response. Unlike typical REST APIs, it generally uses one HTTP endpoint rather than a separate endpoint for each resource.
Discussed at 4:55Queries read data, mutations perform side effects such as creating records or sending email, and subscriptions listen for server-side events such as changes. All three use the same general GraphQL syntax, with optional operation names and arguments.
Discussed at 7:12Install Graphene and its Django integration, define a schema and GraphQL types, configure the Django view with the schema, and add the view to the URL configuration. Django models can be used to generate GraphQL types, and resolver functions can return querysets that Graphene converts into those types.
Discussed at 8:43Define object types for the models, expose fields such as a list or single object through resolver functions, and declare arguments for fields that need them. A mutation extends Graphene’s mutation class, declares its input and output fields, and creates or updates the Django objects in its mutation method.
Discussed at 10:00The speaker describes three approaches: Django sessions for APIs used by the website itself, authentication headers such as tokens for REST-like clients, and field or mutation arguments for cases where only particular operations need authentication.
Discussed at 16:23Possible safeguards include query timeouts, maximum nesting-depth limits, and assigning costs to fields so overly expensive queries can be rejected. Static or persisted queries are another option, letting the server accept approved query IDs instead of arbitrary query documents.
Discussed at 17:55You can send an HTTP request directly, with the query represented in JSON, or use a client framework such as Apollo or Relay. The speaker uses Apollo because it works with multiple JavaScript frameworks.
Discussed at 22:19Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026