Adding a GraphQL API to Wagtail - Patrick Arminio

This video features Patrick Arminio at Wagtail Space US 2022 in Cleveland, Ohio, USA.

Adding a GraphQL API to Wagtail - Patrick Arminio
0:28:36
Published March 30, 2022
332 views

Summary

Patrick Arminio explains how GraphQL can expose Wagtail content, contrasting its single, typed query endpoint with REST’s potential under-fetching and over-fetching. He demonstrates building schemas with Strawberry, mapping Wagtail and Django models, defining custom scalars such as HTML, and representing StreamField content as typed unions. He then presents an experimental Strawberry Django/Wagtail integration that automatically exposes model fields and StreamField blocks with only a few lines of configuration, while noting that it still needs features such as previews and improved image support. He also briefly compares Strawberry with Graphene, arguing that Strawberry’s stronger community maintenance and type-oriented API are important advantages.

Key takeaways

  • GraphQL lets clients request exactly the fields they need from one endpoint, helping avoid REST under-fetching and over-fetching.
  • GraphQL’s schema and tooling provide validation, documentation, autocomplete, code generation, and strongly typed client data.
  • Strawberry uses Python type annotations and resolvers to define GraphQL types and connect them to Django or Wagtail data.
  • Wagtail StreamFields can be represented as GraphQL union types, allowing front ends to handle each block type explicitly.
  • Strawberry Django and the experimental Strawberry Wagtail integration reduce the code needed to expose Django models and Wagtail content.
  • The Wagtail integration is experimental, with planned work including previews and better image support; Arminio contrasts Strawberry’s community maintenance with Graphene’s slower development.

Summarised automatically from the transcript.

Transcript

5,049 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Speaker 1: So it is my pleasure to introduce our next speaker, Patrick Arminio, who is the creator of Strawberry GraphQL. And he will be broadcasting remotely.

0:14

Speaker 2: Yeah. Hello everyone. Nice to meet you, even if it's not in person this time. Yeah, I just shared my screen. So Yeah, today we're gonna talk about you know integrating uh GraphCard API with Bugtail and some of the experiments of doing this work. Um I'm gonna do an intro introduction myself. Um Yeah, I'm my name is Patrick Arminho, I'm the creator of Survey GraphQL, which is a Python library for uh creating GraphQL APIs using type ins Which is a new Python feature. I think it was recently Python 3. 6. It might not be correct, but it's relatively new. But it's becoming more popular. And we're gonna see an example of uh what typing means in Python later in the talk.

0:59

Speaker 2: I'm also the chair of Python Italia. We organize uh the Python Italy and I'm also a member of the board of EuroPython Society and we do uh EuroPython. Um and the reason why I'm giving this talk is mostly because we just launched a new website for EuroPython And uh the website using XPS and um React and we are you know uh adding markdown files to to change the content and we were looking at using SMS for uh just making the life easier of the content angler and not having to um to deal with um uh you know in markdown files and you know we should be tapped into it um and you know the first talk this morning you know why uh waxfell is a very good cms

1:46

Speaker 2: and i think Like my reference on you know on Wagtail is mostly towards the the stream field, which I think it's a really awesome feature. I think it's something that's gonna make our life easier because you know with stream fields you can and find C box that you want to enable for your editors to use and then they they go and use them and the front end uh you get understand what kind of you have then you can you know for example if I you have a block for a card you can you know get all And we have an example here of stream field here. So this is a home page which has a body and is a stream field. So when you click here, you can choose all the blocks that uh I created for this specific thing. So for example, heading, paragraph, image, and so on.

2:35

Speaker 2: Yeah, so this this is why I really really think we should go rebuktel and we're gonna start working on that soon. But all of this also prompted me to, you know, there's something I always wanted to do. I I actually tried to do uh a logged in graphical API I think two or three years ago. I didn't really have time to finish that. But yeah, I'm gonna show you what I've done. this way and in a few seconds but before doing that just wanna you know show a quick example uh of the reason why you should use capital and what actually is So not many people might be familiar with the exchanges of kind of new technology is not as popular as us. In order to you know to make you understand what is i have a demo of an api that i have

3:22

Speaker 2: built it's always already available on the net uh but it's it's it's good to you know go and test something that uh it's you know has a lot of features things you can try So as I mentioned, GraphCard is a way to build APIs for a website or application. And the difference with REST is that with REST you have different points. For example, if you want to fetch a, this is an API for country, if you want to fetch. country with it for it you might have endpoint that's that slash country set slash it and you will get all the data for the country with graphcare things are slightly different you you have only one endpoint and you send a document to the end of the script the data that we want. So for example, if you want to fetch a country here, okay country code 18

4:08

Speaker 2: uh you can get maybe the name things like that um and this is really powerful because it does solve a couple of problems of um of rest Like Kafka is always seen as an alternative to rest. The reason why is uh I think it's because you know Kafka was created by by Facebook and they were trying to solve some issues that are start, which are And fetching and overfetching. I had a lot of you know mobile clients that you know needed to get the DPS as well as possible. So um undersching in in REST basically means that you have an API that's not returning enough data. And to carefully you might need to do multiple data code. So for example, if we have touching here the continent.

4:55

Speaker 2: In a prediction Rust API, like a proper restful API, you might have the content, you can only get the code code the ID, and then you will need to do another API code to go and touch that Which is it's a waste of data because again, you know, you're you're doing two two API calls and there's latency and so And then to solve this problem, you could build an API that returns all the issue that you might need, but then you overfetch them. So let's say that I'm also returning the country here And the name for the countries. If I'm building an API that only needs just the name of the continent and the country And I don't need a list of parameters for this specific content. And I now have an API that's returning too much data, which is overfetching.

5:41

Speaker 2: And again, it's a waste of data, basically. I I think that GraphQL is really powerful for these specific features, you know, being able to declare the data that you want, it makes it kind of makes the API more performant. But to me, the coolest feature and the most useful feature of GraphQL is the type system , which basically means that every GraphQL API has a schema and when you're doing the query you can easily understand what kind of data you you can log. So here um at this this query done testing for getting a list of country based by a currency. And I can see when I hover over it using this tool, uh I can see that the return type of this uh field is a list of country and is not optional.

6:29

Speaker 2: So this exclamation mark means that this field is always gonna be So it's going to return something. Um the opposite side we have a code here for the state, which is a string but it's not uh It's not required, so it's option, and you can see in the the return type that the return data is actually gonna be null. So this makes your you know life easier because you have an API that's um that's basically type safe, so you can You're basically sure that when you run in this period, the data that's coming back looks the way you want. Um And this tech system, the fact that it is a built-in because Catholic is a stack that has all these things built in, it makes um make it your life easier by enabling like some sort of set of tools like for example the graphical

7:16

Speaker 2: the peggard which is this one so you know when I was playing around with this I didn't really have to remember all the things available here because it It does do like you know autocompletion things like fact of them have to remember uh what this API how this API works And then you get auto-autogenerated talks. For example, you can see all the information that you want to fetch. So for example, for continents here, you can see also the argument. You can see that you can feel the code by code. uh things like that which is really powerful um and this is what i mentioned by the schema so every graph card api has a schema which describes all the uh the types in the in the API. So and we have mentioned that there's a special type which is the query which is basically the

8:02

Speaker 2: root type. So all the data that you can fetch from the top from the root is the it comes from here So for example, this continents field, it's coming from the grid type. Other tools that are really cool, I think COGEN is another one which I use a lot Uh this one is Kim Jasper, which is Kafka Prochent here. So this tool basically allows you to transform a GraphQL query to uh code. So for example, you can have TypeScript code for YAP front end which uh you know creates a uh hook that you can easily use without you know just wrapping just the query and then it does everything for you. The cool thing is that it's also typed.

8:49

Speaker 2: So for example, when you're using the sook on your front, you can basically get auto-completion, which is really nice, but also you get the tab chat, which is uh really useful. What I'm currently working on, we are using code gen in a strange way. We are actually generating uh REST APIs on top of Graphical APIs. So we we get an API like this, a query like this You run some code and then we get an endpoint for fast API that returns a GafCad API. We do this mostly because we are transitioning to GafCad and we want to support some older clients that are in this REST. Other thing is like schema validation is really powerful. It's similar to you know just type checking in Python and TypeScript, you get this for

9:34

Speaker 2: you know for your period So for example, if I have a title here, the ID that I'm using, the playground I'm using, is already telling me that there is a title here. But even if I do this, if I try this query I'm gonna have a validation error. So the GraphQL server is not even trying to run this query because it's not valid. So you're trying to flash something that doesn't um not gonna work. And then the last tool, which I think is really cool, is Apollo Federation. And Apollo Federation is basically a way to combine multiple graphical APIs into graphics. So let's say that you have a locked in Kafka API and then you have maybe uh an e-commerce API. You wanna have use both of them on the front end, but you don't want to deal with two APIs. you can use a color of it

10:19

Speaker 2: to combine them to one and so your front doesn't need to know that there's two um two different uh cuts are there So hopefully that you know that kind of makes you think, yeah, FKL is quite cool. I would like to try it. Um But you know Wagtail already provides the REST API. So you might not need Kev Curl for Wagtail, especially if the REST API is good enough for you Um yeah, the reason why you know I'm I'm probably biased here because I work on a Gafkal API and I use Gavkal every day. I am really into the tooling and I use GraphCal a lot. So, you know, for me it's an obvious start to just go and use GraphCal even for Wack Hill But the fact that you have all these tools here, you know, CodeGen, schema

11:06

Speaker 2: validation, polar federation, they make your life so much easier. I think it makes a lot of sense to use uh GraphQL reward and What I've been working on as well with my integration with WalkTale is that these string fields, which they're represented as JSON in the back end. In in a GraphQL API, they're actually not JSON. They actually are typed. So on the front end you can go and say, oh, if it's the type of decent heading, then do something else, which I think is really really powerful. Cool. Just wanted to just give you a quick introduction of what Strawberry is. So I started Strawberry, I think, three years ago, more or less, and it's becoming quite popular. relatively popular I guess

11:53

Speaker 2: now these days and there's a lot of people using it which is quite nice uh when they communicate around it it's uh it's really um welcome and friendly And what did that survey came to be mostly because I talked on data classes , I was at Jungle Corn US, I think in 2018, and there was this talk that was describing how data classes work and what they do. Um and this syntax is very nice. It makes you know writing a class environment so much nicer than uh than normally so like what the class do is basically it reads all the fields that you're listing and then it creates equality method constructor method and so on with just three lines of code which is really nice and then the other

12:38

Speaker 2: Very cool thing is that it's using type-ins. So type-ins in Python, they're like a new feature that allows you to, if you annotate your Python code with types. So in this case, I'm saying that this class user as a field or property, code name, which is a typestream. And then Python doesn't really do anything with it. It doesn't, you know, if you try to instantiate user with um with one for the name as an integer, it's not gonna complain. But if you use tools like myPy or PyWrite, uh you're gonna see the um you know the type checker uh are gonna complain. So you're gonna, you know, you get this type safety with Python as well. But the other cool thing is like uh interesting enough, Python allows you to get information about this orientation at runtime.

13:24

Speaker 2: uh which is one of actually covering covering uh survey. So if you want to make a user that can type the survey almost the same code, you only spot the decorator using a server type. And what we do is basically we go and read all the annotations, get all the fields, we get the types, and then we try to convert this type to a um a graphical type. So I'm gonna show an example how this works. So let's say that we're doing CMA API that we have before. So we have this type user, which is what we just wrote, and then we have a the query type, which is the root type. And in the query type, we have a field for user by ID, which accepts one argument, which is ID, and returns an optional user. To convert this to

14:09

Speaker 2: subright, it's um It's quite straightforward. So you improve server, you create the class for every type that you have, in this case user, or the name is a string, and then you add the decorator. Then the last step is to create the root type which is the query and you have the user by B here which is returning an update user and then the special thing here is that you are attaching a resolver to this field. So You know, you need to tell basically GraphQL to fetch the data for every field that you have. So GraphQL has these concepts of resolvers, which are basically functions that get called when someone requests a field. So if the client is requesting this field, then this Python function is going to be called.

14:56

Speaker 2: And So very needs to uh get the the arguments of this function out then to the um to the front and to the query field. The last thing to do is to create the schemas and survey the schema. That's basically to you know create a small graphical guy and survey And I think this syntax is quite nice and it also pretty much similar to what you would just write in in plain GraphQL, the schema. uh example here it almost looks like you know python just has curly basis and maybe some interesting things here So let's see how we can you know build a quick uh API for for uh for Wagtail. So Let's say that we have this

15:42

Speaker 2: log page model, so we have a body, which is a visit field, date, and a field image. So This is this is how you would make the capital API. I guess it will change based on your usage, but like normally it would be something like this. So we have a type query where you have a field that allows you to fetch a blog page by ID And then you have the field that allows you to fetch all the block pages. And ideally you the paginist search here, but just to keep things simple, I haven't added them here. And then the type for the blog page is you know straightforward as an ID, a body, a date, and a feed image. The only interesting thing here is that the body is of type HML. And in GraphQL you have two kinds of types. So you have object types, which are basically types that have fields, and then you have scalar types, which are types like string, name, date, ID.

16:32

Speaker 2: integer and so on. And HTML doesn't really exist in GraphQL. It's just a it's a type that we create. So uh GraphCl allows you to create custom file. And the reason why we do this is to basically improve the type system. So we know that this body is actually storing the HTML, so we want to tell this to the our client. So when a client goes and reads the body, it knows that it should do something with the HTML. You could do the same, for example, if you if you write Bobby the Markdowns, you could say this is Markdown and your client will need to convert the markdown to also. To convert this to Python and Subway , it's similar to before, but the thing is uh you need to create this color

17:18

Speaker 2: So we're using the server scalar constructor to create a new scalar based on a new type, which is another constructor from Python, which is basically telling the type system that there is a new type HCML, which is based on strict. But what the reason why we do this, the reason why we do the new type is so that when we're using this API, when we 're returning data for the blog page. We have to pass an instance of HM. We cannot just pass a string. This is to make things more type-safe as well. And then for the query, similar to the first example, we create the fields and then we have the resolver. I'm just gonna show the get blog page by D. The Git blog blog pages is pretty much the same.

18:04

Speaker 2: So Here we have this catalog page by ID, accept the ID returns an optional web page, refetching the model, and then if there is no data management, otherwise return an instance of uh graphical type So you can see here that we are returning the article type but we're fetching a pipe from uh well a jungle model. Um the reason why this is not mandatory so you could return the page directly mostly because the the the return type they they had similar shape or almost the same shape so the model has an idea as a date and things like that The reason why there's this kind of bit of code duplication is to uh make this code more type-safe. With

18:49

Speaker 2: white tail, it's fine to just return the same shape of in of the database that we have, because you know it's a CMS, it's built for that But if you're building a more complex Kafka API, you usually don't want to return the instance, the Jungle instance directly, because you want to shape the data in a different way. I just put this in a example to make it clear that you could do both, but it's probably usually best to return the GraphQL type, mostly for types it is that Cool. I'm gonna show the demo this. It's not gonna be much different than what we showed. It's using a different tool graphical. But the the the way it works is the same. So I have a way of fetching all the block pages and then I can get the ID

19:35

Speaker 2: and it becomes the ID and then I can get the title and the body And you can see here if I have over this, it's telling me that this is an HTML string. Um, and so the front end knows that this I can say it, but you know, it knows our problem that this is HTML Cool. That was quite a bit of code to write, you know, it's especially when there are tools like Django S framework or Django model forms. You would like to have a tool that's slightly easier to use or writing less code, especially in this case when we are exposing a model that's meant to be used and as an API. And so we have this extension of Survey, which is Survey Jungle, which basically is similar to Jungle

20:22

Speaker 2: SquareMook in a way that allows you to create a graphical API for Jungle Model. And to recreate that API that we did before, you basically have to do this. So it's similar to what we had, but has a couple of differences. The first one is that using the Django type decursor. and passing the blog page and then you listing all the fields using this photo keyword. So this is similar to Jangox framework and Jango model forms uh the field argument we're basically seeing what the fields you want to expose using this syntax to be uh consistent with our survey works and also to to make it slightly more friendly to type checkers And then the cool thing here is that you

21:08

Speaker 2: used this new separate jungle field, which allows you to basically create a resolver um on top of a uh Django model. So you don't have to write resolver what the codes are doing that for you automatically. Cool. The one thing that you need to do is to tell Survey Django that there is a new Django field. So the way Survey Django works is that uh when you use photo uh for example for body it goes and find this uh field inside the model gets the jungle type the jungle field type and then tries to convert that to um to get code. The issue with that is that it doesn't know of all the you know custom fields like for example for for the rex field for the web third. So we need to basically tell

21:53

Speaker 2: SurveyJung data that exists. Yeah, a few minutes left. So this is basically you know just a quick way to get a Django Django API. Um I kind of cheated because this API is already using Survey Django, but I didn't really draft all the code to uh that didn't done before. Um but yeah it works the same and can do other things. For example you can also fetch block page uh by ID choosing primary that's the same. The issue with this is also there's still quite a bit of code. You know, you have to go and especially set all the fields you need to create the query type and i really wanted to build something that it's

22:40

Speaker 2: more plug and play um and so this is what i've actually done this week um which is this um uh you recall that yeah i think i just released yesterday which is still very well play um and the way this works you install it add it to your apps and then you add the view And that's it. You don't really have to go and do anything else, anything more than this. It's basically really as plug and pay as possible. And I cheated again to be honest. This API is actually using a survey wogtail. So what you've done here is just these three lines of code. That's the package, obviously. And the cool thing of that is that you don't have to go and have support for all the block

23:25

Speaker 2: their fields manually. It's all done for you. And it also supports theme fields. So have another uh model here which is vintage. So again flexible title everything just as before, but then there is a special interesting type Which is this one page body? This is a union type, so multiple things. So this is powered by the stream field. So I have defined a hidden block, image block, paragraph block, and a two-con block. Which is part ahead before here or like this, and then I can go and factor the information I guess the the syntax for Kafka humans are pretty interesting because you have to uh specify the type

24:13

Speaker 2: run effects and then for every type uh you need to specify the field. So two times and that 's all And I really like this because it's you know when I'm gonna work with front ends I can fix the type name is basically the type of the block that I'm getting back Then in in my front, then I can you know just do a switch around this. If it's heading, I return the heading. If it's uh uh body to columns, I return you know I grade with left column and right column, etc. I think it's really, really nice API to work with, especially because it's type

24:59

Speaker 2: safe. And I guess you can also build checks in your code where you know if you have a new field, you can get a warning and the front end, you know, you should handle that. So that's a good thing. You know, if you haven't handled email, you can work and do that. Um so yeah, that's that's pretty much what I've done this this week, and I'm honestly really excited about this. Hopefully I mean I have already a bunch of issues here that I don't want to do, like improving adding support for previews, improving support for image and things like that. This is very experimental. I mean, I really did this in a couple of days just to prove that it works. So if you if you want to try, hit me up. Really looking forward to people to try this.

25:45

Speaker 2: You can reach me out here. There's all my links. And if you want to try surveying , feel free to jump into the Discord. Yeah, we're happy to have people in chat about GraphQL and even random stuff sometimes. So yeah. Thank you for uh patient to my job and yeah, happy to take questions if there's any

26:11

Speaker 1: Thank you so much. And we get to see another cat. Thank you so much for your talk. We have uh about two minutes until our next speakers. So I think depending on the length of questions, that might be one or two. I did have one, but if there's others in the in the chat or in the room, let's take those first. Did anyone have any questions in the room? And what about on on jet? Well, I had one. I have experience with uh headless wagtail, but just a little bit. I don't remember all the nuances and when I uh when I did it. But I remember uh using graphene. Could you uh speak to how they're different or similar if you have the context?

26:54

Speaker 2: Yeah, I used to be a contributor of graphene. One of the other reasons why, I'm sorry. Um surveys because of the lack of you know community-driven uh work for for graph in so that that's that's that's the main reason why I uh worked on survey other than you know changing the API and having something that's a bit more type safe. Um graffine is is quite nice. I think it's definitely more popular than Subberry, at least for now. And you know it's I I mean it's hard to you know to talk about it like a compilator, but you can you know graphene works works well. It's just a how slow and The the development has slowed down quite a lot, especially in the last couple of years. They took a long time to release Graphene 3. Um

27:39

Speaker 2: and it's a bit of a shame because you know it was really powerful library. And you know the dishes that there was no no many not many people that were able to maintain the library, unfortunately. We took a different approach with Surbery. We tried to make this as more community-driven as possible. So we have loads of maintenance actually. Well no sorry, loads of contributors have quite a few maintainers. Uh because we try, you know, to to make things as funny as possible. So that the for me the main you know the main difference is the community. In terms of API, we I think graphene does have more you know extensions, but we get in there, especially with the jungle language I think is quite nice. I don't know if that explains.

28:24

Speaker 1: Yeah, thank you so much. I appreciate that. So thank you for your talk, and we'll be uh announcing our next speaker.

Questions this talk answers

What is GraphQL, and how is it different from REST APIs?

REST exposes multiple endpoints, while GraphQL generally uses one endpoint where the client sends a query describing exactly the data it wants. This helps avoid underfetching, which requires multiple requests, and overfetching, which returns unnecessary data.

Discussed at 3:22

Why use GraphQL for a Wagtail API?

GraphQL provides a typed schema, validation, autocomplete, generated documentation, and client-code generation. It also lets clients request only the fields they need, and Wagtail StreamField content can be represented with explicit types rather than unstructured JSON.

Discussed at 5:41

How do you create a GraphQL API for a Wagtail model with Strawberry?

Define Strawberry types for the Wagtail model, create query fields such as fetching a page by ID or listing pages, and attach resolvers that retrieve the Django data. The example maps fields such as the page ID, body, date, and featured image into GraphQL types.

Discussed at 15:42

How does Strawberry Django reduce the code needed to expose Django models in GraphQL?

Strawberry Django can derive a GraphQL type from a Django model by specifying the model and exposed fields, and its Django field resolver can fetch model data automatically. Custom Wagtail fields still need to be registered so Strawberry Django knows how to convert them.

Discussed at 20:22

Is there a plug-and-play way to add a GraphQL API to Wagtail?

The experimental Strawberry Wagtail package is intended to be installed, added to the Django apps, and connected through a view with only a few lines of setup. It supplies support for Wagtail fields and StreamField types automatically, although the speaker notes that it is still very early and incomplete.

Discussed at 22:40

How are Wagtail StreamFields represented in GraphQL?

A StreamField is exposed as a union of the possible block types, such as heading, image, paragraph, and two-column blocks. Clients query the appropriate fields for each type and can switch on the returned type name to render the block safely.

Discussed at 23:25

What is the difference between Graphene and Strawberry GraphQL for Python?

Graphene is more established and has more extensions, but its development slowed and Graphene 3 took a long time to arrive. Strawberry was designed around a more type-safe API and a more community-driven development and maintenance model.

Discussed at 26:54

Note: 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.

More videos by Patrick Arminio

More videos from Wagtail Space US