Can't get you out of my head - Aaron Bassett
Published September 30, 2020
This video features Aaron Bassett at DjangoCon Europe 2021 in Online.
When I first heard of GraphQL, I had a lot of questions. How is GraphQL different from REST? What're the benefits? When would I use it instead of DRF (Django Rest Framework)? Can I use it with my existing Django models? What about my views? My permissions? Is it difficult to integrate with my frontend?
REST has served us well for more than twenty years; of course, I would be wary of any technology which requires a total paradigm shift. In this session, I will answer those questions and hopefully alleviate any apprehension about trying GraphQL.
We'll look at a working example of an RGD stack, showing how you can continue to use all the power of your Django backend while rendering and querying your data in React via GraphQL.
Aaron Bassett builds an e-commerce order dashboard with React, GraphQL, and Django, using Strawberry on the Django side and Apollo on the React side. He explains how GraphQL types combine data from carts, users, addresses, and products, while resolvers fetch and transform it, calculate fields such as order totals, and support queries, filtering, and mutations. The examples show how clients request only the fields they need, update order status, retain normal Django models and admin functionality, and connect a React development server to Django with CORS and a proxy. On the frontend, he replaces static data with Apollo queries, loading states, reusable components, and an order-card layout before the recording cuts off while explaining the user-order drawer query.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: Oh, somebody is saying signed is fine I. See working I signed. Hooray, we can hear you. Great. Hi everybody. Yeah, it's um always fun to be one of the first ones on uh any kind of online um conference. You get to be one of the uh uh The testers helping me get some of the bugs and snags I die. So yeah, welcome to my session on getting started with uh Django GraphQL and React. I've actually kind of like in some of the places you'll see I've flipped it around to say React, GraphQL, and Django. Just because I like the fact that then you get the initials RGD, which I can pronounce as rigged.
Speaker 1: So if you hear me talking about like rigged, that's my shortening of React, Raphael, and Django. Um so hopefully you can see my screen as well that it's not just me up here. Give me a thumbs up in the the Slack if you can. And on the screen, there should be a um a GitHub gist. So I know GitHub just has got these incredibly long URLs, but hopefully with the magic of buffered tweets, there should be one on my Twitter. Yay, there we go. So this is going to be um it's on my Twitter uh which is Aaron Bassett like everything else everywhere is Aaron Bassett because I have zero imagination when it comes to
Speaker 1: picking usernames. But yeah, on my Twitter you'll find a link to this gist, which contains everything that we're going to need today. So it is a very short session. There's a lot to cover. You know, we're covering the entire stack essentially. So our back-end server, creating the API, and then connecting that to React. So covering all of that in like 50 minutes. There's quite a lot to cover. So I'm not expecting you to code along with me or to follow along with me as I do this. But if you did want to go through the code in more depth later, it all is published. It's up on GitHub. The link to the repo is in that gist. I've also included the link to some of the other things that will be helpful for you, such as Strawberry, which we're going to go into in a moment. That's the GraphQL library that we're going to be using.
Speaker 1: Also a couple of things drawing can react, the UI libraries I'm going to be using there, and some of our just kind of like helpful links and things. I've also included my social links there, and one of the ones that's probably most relevant would be my Twitch. So for those who don't know me, I'm a principal developer relations engineer with New Relic And that means that I spend most of my time on Twitch live streaming. Uh and I live stream about a bunch of stuff, mostly just Python. It's a weird kind of job where I get to just go online and Build stuff in public and learn about things and teach people as I'm learning about it. And one of the guests I had on this show was Patrick, who is one of the authors of uh Strawberry, which we're gonna be using later.
Speaker 1: And that really piqued my interest as to kind of using GraphQL at all. Like I'd never really used it before. I'd been aware of it for a long time. I got an awesome sticker from Patrick at a conference many years ago. The That's just the strawberry logo is pretty awesome. Like that's a great logo. Let's pull this up a little bit so we can see it. I got it as a fantastic logo. Um and like any other that programmer, I am a sucker for a good sticker. My laptop's covered in them. So I picked this up up from him at a conference many years ago and then just never really got a chance to to kind of play with it or play with GraphQL Until I started doing a streaming job at New Relic and I was, you know, I get in the stream by whatever I'm interested in. So of course I invited Patrick on the stream.
Speaker 1: We streamed together for a while and he kind of showed me the uh kind of getting started with with strawberry and Django. And since I've used that a little bit, but this is still very much an introduction. You know, I'm still pretty new to it myself. This is just how I would explain it as somebody coming from a really Like a REST background. You know, that's that's what I've done most of my work in. That's what I'm used to. That's most of the APIs that I work with are all REST-based. And kind of The differences I see between REST and GraphQL and some of the advantages of it as well. So let's let's look at what we're going to be building today. So this is a little demo that I've put together It's um something that you probably have
Speaker 1: built or used or come across many times before. It's like an e-commerce cart. And this is um I'm imagining like a dashboard that somebody who's running an e-commerce store would have that they can interact with. And you can see there's different orders that have come in. So we have the the name of the person placed in the order, the order ID the total value of the order. Then we have each of the items that's in the order, and then we have a status of the order. And we've got a little few little interactive elements like we can click on the person's name. And it brings up this like quick look panel where we can see all of their previous orders and the status often. Pretty straightforward, good demonstration of Uh being able to drag with an API. Now way in which I've structured this, if we look at the the repository
Speaker 1: Is um that I have all of it broken down into kind of commits that really went through how I would build this up myself. So what I'm gonna do uh throughout the this tutorial today is I'm gonna go step back for each of these commits one at a time or skip a couple and look at how the code is structured at that point. So let's bring up my terminal, which is running the application. Let me clear that and let's go into our get log and we can see the very first one that I have is Django boiler plate. So I'm using Cookie Cutter Django. It's a nice template. It's linked in the gist as well. That sets up a lot of the the boilerplate for creating new Django application for you. So we're not going to go through that.
Speaker 1: It's reasonably standard stuff. So let's skip straight to creating our different um applications in. So I'm going to check i dot commit and let's open my editor now Might just come across as a little bit like any typos and frazzled moment is because it is currently 3. 56 a. m. for me. Uh Yeah, I I moved to America before the pandemic and just kind of stayed here. So I'm no longer in a European time zone. Um no, I have not been to bed yet. Uh I have drunk an incredible amount of coffee though. So hopefully we'll make it through the entire session.
Speaker 1: But if I do pause or stumble a little bit or if I have a lot of typos, I'm gonna blame it on the sleep deprivation. So we got our code open. I have this RGD, you know, React GraphGL Django project I've created here. And within that, we have several different applications. So our cart is gonna made up Let me see if I can bring up that thing again or it's gonna be dead now. Oh, our cart is made up of, as I said, you know, we have our user, we have the products, we have like a status, we need to know where it's being shipped to, all that kind of stuff. So one of the first things we have then is in our cart, let's just look at what the cart is itself. We can see that it has a foreign key to a shopper, which is going to be our user. It has a foreign key to an address where we're going to be shipping the products, and then it has this many to many field for
Speaker 1: products themselves. So the shopper is just using like the regular User model , address, we have another model in here, you know, where it's I'm just defining a name, who we're shipping it to, their street address, their state, and their zip code. And then we have the products. Which all the products are gonna be t-shirts. So we have a size for the shirt, we have the cut of the shirt. And then we have some more information about it. You know, little name description, a photograph of it, how much we have in stock, twice. All common things you may find in this kind of uh application And then if I was in building this out as a REST
Speaker 1: API, you know, so I have a client connecting to it, whether it be a web browser or a mobile app or any of those kind of things. Normally a way I would structure this is I would have a separate API endpoint then for each part of this. You know, I'd have one for my cart. So I would make a request for um to my her endpoint and it return you know this data then it would make a request to my user's endpoint and get uh references shopper Then we'll make a request to my address endpoint, get the address, and then to the product endpoint for each of my products. So there's a lot of different API requests that are going on there. But with uh GraphQL, it's a little bit different. And this is kind of where I think the first of the the strengths of GraphQL comes free. So I'm going to check out
Speaker 1: my main branch again. So I can do a get log and get my next one, which is the GraphQL queries. So let's pick this one up. And so look at our code again. So now I have a new folder and under here called API. And within our API, I have an orders. So I'm no longer going to be requesting each individual model or have an endpoint for each individual model, you know, one for my products, one for my users, etc. etc. I'm just not going to have this orders. It's not an endpoint, but we use that terminology to keep things familiar. So within the orders then, first I'm going to define some types So I have an order type because an order doesn't really exist. An order is going to be a collection of information.
Speaker 1: You know, some of this information coming from the cart, some from the product, some from the user, some from the dress, etc. We're building this all together and an order we can show in the dashboard. So the first thing we have is an ID. This is going to be the cart ID, so I can reference it. We have the name, streets, the zip code, these are all going to come from the address. We have the products, which we'll look at the products type up here in a second. And the products is going to be a list of individual products. Then we have total. Total doesn't exist on any of our models. You know, we take a look at our cart here and we have a look at the model. We don't have a total. You know, each of the products. We'll be open that up again. Each of the products has a price, but we're not totaling that up anywhere. You know, it doesn't exist as part of any of our existing models.
Speaker 1: So that's going to be something that we're going to actually calculate and send as part of this. Um as part of our graph QL. And then we have status, which could come from the cart as well. The products then just lists out kind of all the things that come from the products. Now I I'm writing these all myself. There is a listed in here. Another package you can use, which will take a lot of this boilerplate again away from you, you know, which will do this kind of stuff for you. Um I'm not going to talk about that today, but just be aware that is the gist Gives better integration for graph for strawberry within Django. Takes away a lot of, well, as you can see here, it's listing some of the things, you know, type generation from models, filtering, pagination, ordering, etc. You know, so a lot of the stuff that I'm going to be covering today, this kind of boilerplate is already there.
Speaker 1: Think of it kind of like generic class-based views, you know, that's there to use as well. But at the moment, I'm like writing my own views, as it were. Okay. So back to our types. So we have our types defined. We have a product type which is listing all things that are in our our model there. And then we have this order which is combining things together. So it's combining information from our cart, from our products, from our user, from addresses, all putting it together. So once we have our types defined, then we also have to define our resolvers. And these are the things that are going to be called. They're kind of like views, like URL handlers. Whenever we execute a query against our GraphQL API, it's the resolver that then is going to
Speaker 1: take that query, fetch information, do whatever transforms we need, and then return it back. So in the resolvers, we see here that I'm importing the types. Because we are using a custom user model, I'm going to be using this get user model, and I'm also importing my cart. So um The first thing I've got is this compile order. Compile order is a utility method I've written to allow me to take the information that's coming from my Django models. And transform it into the different types that I need. You know, so it matches, so it can create a new product type and create a new order type. So we can see here it takes a cart instance. And then we are getting all of the products that are attached to that cart.
Speaker 1: And for each of those products, then we're just creating this new product, this product type. So we can see here it's really just mapping almost one-to-one Our order total that we talked about a second ago, the fact that we have this order total that's available on the API that's not part of our models, this is where that's being calculated. You know, so I've been computing this here where I'm taking the price of each product for all the products on that cart, and I'm summing them into the order total. Then finally I'm returning the whole order, which is going to be some information from the cart. We can see it's got the cart ID, it's got some information about the address here. So we've got like, you know, name, street, state, zip code, et cetera, the products that we compile at the top here. And then our order total that we computed and finally the cart status.
Speaker 1: And this is all being returned in anytime we call this compile order. So it's just a utility method I've written to help me map the model data to the types of returning. And here are the actual resolvers themselves. So I've written a couple different ones as examples. The first one is our get order. Which is going to receive an order ID and is going to return a single order. So here we can see we're just we've got this ID and we're doing just a cart object scan. Our get orders doesn't take any variables and it's just going to return all orders. Then we have um get orders for user. So here's where we can do you know, some kind of like filtering and we can start drilling down in different information that we require. And within it we've got this, you know, it takes the ID, this time it's going to be the user ID, it's going to get that user, and it's just returning
Speaker 1: Any carts that are associated to that user. So we're using just a regular Django filter here to filter the results or the results set from our query to only be for that one individual user. And then get open orders. Very similar again. This time I'm doing the cart to open the all because on my cart model you can see that I'm actually using the St model from Django Model Utils. And that will create the that handler for me. So I can then just do my status of cart. open. all and it will return only those that have the status of open. So very similar to how you would write kind of custom views, you know
Speaker 1: list whatever data you need and then you'd be returning it to Normally to your template renderer. And this time though we're building up an API and we're going to be returning that as part of our graph shell API. So once we have all of our resolvers uh written, then we need to find our schema. Here you can see that I'm importing all these resolvers. I'm creating a new uh class called query, and then I am defining my schema here. So I'm seeing that know my order this an optional type order and it's this is a resolver that uh I'm gonna be using for orders resolver get orders orders for user, get orders to user, etc. etc. all the way free. Then once I have these all defined, I can then pass in my query
Speaker 1: So I create my schema and then once I have the schema in this much the same way as you would touch any other kind of URL in Django, we can see in my URL subpine here that I've got this new graphic real view. which is called as view and I can pass it my schema. And this is just imported into my regular URLs. Here You know, so now I have this API endpoint that I can use to start querying GraphQL. So let's start up our server and give it a go. I I think I might still have this running, which I'm going to kill. It's going to keep querying it. It's not going to work very well. Yeah, let's
Speaker 1: clear that. And And we're gonna try that again. Okay, so we now have this running. And if we go to our API endpoint, we get this lovely like interface lies to query our GraphQL API I have installed the, if you look at my requirements here, um strawberry library with debug server enabled as well. So Let's write our first query. So we are going to have our and we get this lovely autocomplete for it. So we're just going to look for all orders.
Speaker 1: It doesn't take any remember our resolver here, if we look at our resolvers again, you know the get orders doesn't take any arguments. It's just gonna return all orders. And this is where it gets interesting. If I was requesting this off a regular REST API, and I just hit the list endpoint, you know, forward slash orders, whatever it's going to be, and it returns me a list of all orders. It's gonna return me all of the information. So that would be in in this case, you know, we would be getting all of this plus every product and every order, total status, all all of the data all of the time. With Graphic Reality, you don't need to receive all the data all the time. Instead, you specify which data is you're interested in. So say for example, in this instance that I want to just see, you know, I don't really care about the individual products.
Speaker 1: What I do care about is the what state the order is from, the total um amount that the order was for, and the status of the order. So I can just specify that in here and go, okay, well I want to state. You know, I want the what do they say, the total And I want the order status. So I can see how many open orders I have, you know, per state and what the total of them is. I can run that query, and we can see here that I'm getting back, okay, for you know I don't know what the American states are. For each state, I have my total and I have the status off it. If I wanted to drill down a little bit further, let's say that I also wanted to, you know, I'm not so much worried about this information.
Speaker 1: Well no, let's bring in some more stuff. I want the ID of the order. And then I also want to look at the products that they're getting as well. So I can add that onto the end here. I can add it like products. Now because products itself is part of this product type, I can do the same thing again. You know, I don't need to request all the information. Maybe I'm just interested in whether or not the products are in stock and their name. So I can go, okay, well give me the name of the product and the current stock. So I can make sure that like all of these orders that I have here that I can see what products are in them and ensure that we currently have enough stock to Complete that order. So I can just lift out just the information that I need. And this is really, really powerful. Because it means then that one, we're assisting bandwidth costs.
Speaker 1: You know, and I know that might not seem like a big overhead to be sending like this data or to you know all the data all the time. We think for every single request, especially now where everybody's moving online and we still have places in the world that have data caps. looking at my friends in Australia. Anything we can do to stop sending unneeded data um to our users, it helps their data caps. Humps, our are limits as well. But it's not just that, it's it's also then when you're on the front end, I can add additional things to my models. I can add new new fields to my types, etc. And it's not going to interfere with the front end. You know, if if I was doing it with a REST API, And I simply wanted to go for like my products here and I was just going to iterate over the object that's returned and just print everything to
Speaker 1: screen. Well, if I added a new thing to products and I was just doing it in that way where I'm getting everything all the time, well I'm now printing out something that I wasn't expecting. Whereas here I'm only getting the data that I've asked for. So um we Have our different uh products, we have our different orders, we have our resolvers, but all of our resolvers that we looked at so far are of the read type. You know, we're not doing any Creates, we're not doing updates, we're not doing any deletes. We're not doing anything that's making any changes to the database or any reading from the database. But we can also do what's called mutations. So let's check out our main branch again. But I can do my get log and let's look and see.
Speaker 1: So we got GraphQL queries, but then we've got GraphQL order mutation. So I'm going to pick this one up. And let's go have a look at our resolvers now. So actually, first thing I need to do is I need to change my type. I have a new type now, which is an this input, and I have this update order status input. And within this um input, you can see the only thing that I'm Align and update is the status of the order. So we're still looking at that kind of dashboard where it's displaying all the orders We're not going to be creating the orders for you there, but I wanted to have some kind of way of demonstrating the mutation. And this is like something you may want to do on an order dashboard is have a quick way of being able to change the status.
Speaker 1: Order has been paid and you've shipped it out. You can go in there quickly, click a button, change it to shipped. So in this one, we're only thing we're allowing people to change is the status. And then in our resolver for it, We can see here that we have this update order status. It takes an ID of the order. It takes our input that we just defined. And then we're just doing a filter for parts of said ID and update the status to be our input status And then it's just going to return the the order that we just updated. So we're just using that CM get order resolver from up here, and we're just going to return that. In our schema, we now have a new type of mutation. And we can see here that we have got our update order status, which is going to you know
Speaker 1: return an order, and then we have our mutation, we're defining our resolver of that update order status. And we then pass that into our schema. And we don't need to do anything else. So we didn't need to update our URLs. It's still receiving the schema. It's now part, but it's now part of our GraphQL API. So if I restart my server. Does anybody else do that? You know it'd be m you know it probably would be faster to like just type the command again, but you know it's somewhere in your history, so you're gonna be hitting the hot arrow. Like if you may hit the hot arrow three times more than it would take you to like start typing the command and tab complete it. But yeah, it's a really bad habit I need to get out of. Okay, so I now I have uh my new Mutation. I'm going to refresh this just to make sure that I get my nice uh autocompletes and stuff.
Speaker 1: So this time I'm going to start off by saying it's a mutation. And then in here I'm gonna do it's like an update order status. And I know it's gonna take a few values. It's gonna take an ID. So let's give it ID of one. I know there's an order for that ID. And then it's going to take an input. And the input is going to be in another object, which has got a status. And I'm going to change the status of this. I don't think there's any I saw there that the status of canceled. So we'll need one canceled. Now this is telling me there's still An error here because this is going to return me an order. And like we had before, I need to tell it what fields I want from that order. You know, so it's going to return the same Type here and again because this is being returned, we saw as a resolver here, I get to
Speaker 1: I get to pick What fields I would like to get back again. So I'm really only interested in the ID and the status, so I can check that it has indeed been updated. I can run that now and we can see there is our update order and we've got our ID of one with state is cancelled. Great. So if I go back to the history, isn't that really a handy feature? So I've got history in here and I can do you know let's let's grab our orders one that I had and let's run let's put our ID in here as well. So we're last time we had an ID of one. We can run that We see our ID one down here. Yep, that's set to canceled. Let's run our mutation again. And we're gonna change this. Oh, we made a mistake. That should still be open.
Speaker 1: Run it. And if we check our orders again. You know, it's now back to open. And the other thing about this is like as well as interacting it through here, I've just got my regular Django admin set up and I can see all of these in here too. You know, so there is our what's this one maybe? Order ID one? Yeah. You know, so set to open. And I can make like the changes in here, same as you would, you know, any other time. There's nothing different about my Django models than usual. You know, so here we go. So change that again to paid. It's just your regular Django models. You can still interact with them through the admin as you would, free like management commands. all that kind of stuff. You know, there's no difference there. It's just this API layer that we're putting on top of it that we can interact with.
Speaker 1: So now we have our GraphQL resolvers for our different reads and also a mutation. That's that's probably kind of it for Shango. Like it's um I hope to think quite straightforward to add these on. Now these are very simple examples or very kind of uh They're not very complex examples. So I'm trying to avoid using that kind of language. Don't want to call this any of this the simple because It's not, except we know how, but it's yeah, so it's not complex. Let's put it that way. These are not very complex examples where we're I'm not doing any kind of error checking in them either.
Speaker 1: There's nothing here to check to see if an ID exists. In fact, let's Let's see what happens if I do a query. So I'm going to grab an individual order this time. And I'm going to give it an ID. And I know there's not a hundred in there. Uh let's just return ID. And this will probably be very broken. Let's see what kind of thing it gives you whenever you break it. Yeah, so it does give me some nice error error messages uh by default. You know, I can see here that matching query does not exist. I've not programmed any of that kind of stuff in. So it's nice it does catch that and return it for me. I think it also will do it on, yeah. So here we go. You know, I've got my uh exception being uh thrown here. Not the neatest way of handling that.
Speaker 1: I wouldn't ex I wouldn't suggest that you just let your exceptions uh get thrown like that in production, but you can see that even without any great error checking that it does at least give me a pretty decent message. back to. So yeah, as I said, these are pretty um not complex examples where I am simply lifting out One um item, I'm not doing any major transforms, I'm not even doing authentication or anything like that on them. But it should give you an example of How you to get started with the GraphQL. Now on the front end, let's this is where it gets fun as we now have two terminals running. So let's check out our main here.
Speaker 1: Uh you got our mutation. So very much like I used the Cookie cutter to set up our Django application. I'm going to set up a React app with Create React app. For anybody who's not used React before, Create React app will just generate a some boilerplate code for me. In fact, let's just see what that looks like. Before we go much further. So now I have as well as my I've separated them into two separate folders, one for the server side, one for the front end. I mean you can see here in the front end I now have a a few different files. The most important one being this source file which has, you know This is the the default Create React app. You can tell it's a default Create React app. I've not modified it because it still has a semicolons.
Speaker 1: You don't have the semicolons. But this is just a default file that comes in Create React app that will just display a React logo. Uh so everybody's not familiar with it, that's the structure and things that it creates uh just from that set that same command. So this is a pretty familiar structure you'll get in a lot of React apps. Okay, so let's check an army and I can see So the first thing I I normally do is I create a lot of the UI just statically, just so I can Um so I need to start up my Python server again. So
Speaker 1: And I need as well to start my React server. This is gonna take a little second while it compiles my React app and starts up. So let's look at the code while it's doing that. So now in my app. js we had open, you can see it's it's grown a little bit. It's kind of messy. A lot of the information I have here is just static. I'm not doing any, I'm not fetching anything from the server yet. I've just created a bunch of lists or sorry a bunch of arrays and objects with some static information in them that I'm going to display on the front end. This is just allowing me to do a little bit of the UI work. With the UI, I'm also using ant design, so
Speaker 1: that I don't need to do any design work myself. It's also listed here in the gist And that design is a kind of UI framework for React that has a bunch of pre-made components. A lot of them you'll see listed here. The card is the main one that I'm going to be using today. If we have a look somewhere down here, it's gonna say card, card. And we can see it's got like different examples of cards and the code to create them. So these components here are not ones I've created myself. It's all part of this ant design component library that I'm going to be using to render the front end, which at the moment is going to look something like this. So you can see that's similar to what we looked at right at the very start.
Speaker 1: It has the You know, the user's name, the order ID, the order total, a list of the the products that the user is purchasing, and the price per product, and then the status. And these are going to be buttons. Now at the moment they don't do anything But we want that whenever we click these, it's going to run that mutation and it's going to change on our update the model in our database, et cetera. And then we also have like the ability to click on the person's name And we get this like little kind of drawer at the bottom that allow us to very quickly see all of their orders. And we can see the orders here. They don't have the same information. Now we're just looking at just the ID. And then some of the address, a very limited amount of the address information, just like what state it's in, the total of the order, and the status.
Speaker 1: So then this is like also filtered by user. So let's so this is all static. There's no information from the server. You can see here, like there is the products. Match these products and we can see here is the the ordered data that matches the data down here. So I've just I've just got it hard-coded into my template at the moment to allow me to render out and see a little bit of information about it. So the next thing we want to do then is to start fetching that information from the server itself. So No, if I immediately try and fetch the information from our Django server right now, it's not going to work.
Speaker 1: And the reason for that, well let's look at let's look at um our server first before I check the site. So Here is our Django application, it's running on port 8000. Here is our React application, it's running on port 3000. Okay, so CM server, my local machine, but we're running on two different ports. So as far as cores is concerned, it's two separate origins So if I was to attempt to request from this origin , like make an API request to my Django server, which is running on a different origin
Speaker 1: right now, it's going to fail. And that's because if we look, let's look at my console. And let's replay one of these. Oh, sorry, look at network. Yeah, so we can see here we have like our response header. Um, oh So I've already updated it. Sorry. So we get this access control ally origin asterisk. So that's what we want to see. Um and that's that means essentially that Our server is saying you can access it from anywhere. Now you the reason we have that is let's Yeah, here we go.
Speaker 1: Am I seizing another oh server server again? We're gonna need it in a second. So in my Django server, in my uh settings, we will see That I have this course middleware and course application install. So it's gonna send the correct course headers to allow my front ends to request data from a backend, although even though they're on different origins And what I'm doing is in my local for my local test environment, I'm setting that course lie origin all to true. So it's going to allow requests from anywhere. This is not something I would recommend in a production site, obviously, you know,
Speaker 1: but for this example, I'm running it in my local. I can live with it. So this is going to allow me to request from two different origins. So from the request coming in from my front end on port 3000 is going to be able to access my API on port 8000. I don't want to have to uh anytime I'm requesting through an API, I don't want to put in the full URL. So what I'm actually doing as well is in the Front end one in my package adjacent is I have this proxy setting. So my React application will know the proxy in a request for URLs that it's that that it doesn't recognize free to my other server, free to my Django server. And in order for that to stick, this is one of the times that a low
Speaker 1: React will automatically reload. is you do have to reload your server to allow changes from your package. json to take effect. That has stung me before. So let's go start my development server again. I should also still have my Python server running. Great. And hopefully now we should actually start getting some live data from the server. So before I started the stream, I went in, or maybe not actually. Oh no, I've just sorry. I have only so the core stuff I need to actually do one more pecai. Which is connects the front end and back end
Speaker 1: Here we go. Great. So now we're seeing we're actually getting some real live data free from the server. Before I got on the the stream started, I went and added some just some fake data to my application. We can see it in here. You know, so in the admin we can see I've got you know some fake carts and the fake carts have You know, fake statuses and products, and I have a bunch of products I created in here, you know, so all different t-shirts and prices, etc. And that's what's being pulled out in this front end. So these are actual like Orders that are that exist in my um Django application at the moment. And we can filter them the same way as we did before, or we can click on one. You know, and it brings up my little thing. And again, this is showing me the
Speaker 1: the orders just for that user. And what that looks like in the React application is I'm using a Client called Apollo. And Apollo seems to be the kind of de facto client application for React. Most places when I've looked at using React with GraphQL, this is one they recommend. And Apollo, um if we look here in my index of JS, I'm creating my Apollo client. And then I'm supplying that as a provider to React. So for people who are not overly familiar with React , there 's different ways in which you can pass information down from component to component. You can pass it as props. or you can create like providers and then wrap your child components in that provider.
Speaker 1: Because my my app, which is going to contain all of my custom components, is wrapped within this Apollo provider, then it's going to be able to access that Apollo client to make the requests. So in my app. js, I've tidied up a lot, as you'll see. There's no longer any of that hard-coded information in my app. js instead of broken all into these different components. So the first component we'll look at is the orders list. And the orders list is going to do you our first query. So we can see here we have our Apollo client that we're importing, and we also have this graph query language all orders, which is a query I've written here, and we can see that it looks very similar. to the kind of queries that we are writing.
Speaker 1: Let's move this out of the way. The kind of queries we're writing in this interface. Very, very similar indeed. So we have our query. We got our um the type of query we're doing, we're creating orders, the information we want from the order. So this is gonna be the information that's displayed. on this card, you know, so name, yep, name, user ID. So we can click on it to filter these by the user The idea of the order itself, just here. The total of the order? Yep. And then products. And for each product, we want the photo, the name, the size, the cut, and the price. So we've got the photo, the name, the size, the cut, and the price. And then we also want to I have the status of the order, which wanna use to populate these And
Speaker 1: once we've got like all of our or our query written out, we can see that it's getting passed into our Apollo client. And we have a few different Things are being defined here. We have it's gonna return a loading status, error status, which I'm ignoring, so I'm not doing any error checking in this at all. And then the actual data, and this is where the information from Our GraphQL API is going to be passed into React, or is going to be available in React. And this will be run whenever our component loads, you know, sorry, whenever a component is mounted. So as soon as the component mounts, this query is going to be executed, and we're hopefully we just see it populate in that data. While that query is executing, then our loading will be set to true. As soon as this is finished, then that'll be set to false. And that's all we're doing here is this checking if loading is true. And if it is, then I'm putting in a little
Speaker 1: Placeholder with a spinner. And we can if I refresh this. Yeah, you can see it here. This is that loader that's getting put um in place. We'll do it one more time so you can see you know it's fetching orders. And then once That loading changes to false, then we no longer render this. We start rendering out the rest of our component. Our GraphQL API is just gonna return everything as one big array. But I want to split it up into columns. So I have a row here, and each row has three columns in it or three cards. So I'm chunking it, my array at three. So I'm creating an array of array. Then I'm iterating over the
Speaker 1: each item in the first array which is going to be my row and then I'm iterate over each item within there and that's going to be our individual orders these cards I've now defined an order card component to make things nice and neat. And the order card component just contains the different elements needed to create this. You know, so we have our button with our pick event to open the drawer. You know, it's just gonna open this here. We have you know our action buttons for the different statuses. And then we have the actual list itself, which is going to print out our list of products. Now, the interesting thing with our short order drawer for user is that we are doing another fetch here of an order But this time we're we're using that you know
Speaker 1: uh all orders for a user and we are not showing the same information. It's still an order, but now we're displaying different information for it. So in our query for that you can see we're only return we're only requesting the fields that we require. So ID meme state total st you know some different information than what we um query or sorry what we're querying before so the final one then is at the moment these don't do anything. You know, they're not actually uh sending state anywhere. So let's go. Uh we are gonna check out our mean brunch. And
Speaker 1: oh, in the wrong folder There we go. Let's just make sure our Python server is up to date as well. Starting our development server. So it is the yarn one that takes a little bit a little bit longer to start. Okay, so we have that started. Pushing our orders. And now I can actually update these. So clicking on each one will update this DAS. And if I go back to my GraphQL, let's write another query here. So I want just all orders
Speaker 1: and I want the ID and I want the status. So we can see that they are being updated. Okay, so ID one is said it's delivered. Let's go back here. ID one. Uh no, I got that wrong. It's just shipped. It's not delivered yet. So we're gonna change it to shipped. Rerun our query here. And we're not at shipped. So look at it in our Django admin shipped. So everything's all nicely linked together. And if I make changes elsewhere as well, so let's say that, you know, I see our mutation here. So I'm going to do a mutation, I'm going to update order status. Let's update that order one again. Um let's change our
Speaker 1: uh status to be cancelled. Let's return our ID and let's do this again. You know, update it here. RD1 is not canceled. Let's still look at our front end. ID1 is not canceled. You know, so everything's all nicely linked together. Let's just for completeness look at a Django admin cancel So that's really, really quick introduction. As I said, we're with only 50 minutes in time for questions, so I will be hanging around for a little while. It is half four in the morning So I can't promise how long I will be online for. But I'm gonna join, I th
Speaker 1: I think there's a link on the the swarm page for my talk. There should be a link at the bottom to join face to face, I think it's called. So I'm gonna go hop on that to answer questions there. Also check out the Slack um for the secondary room. Hopefully people been commenting, et cetera. But what I would also like to point out is on my Twitch, um, I do stream an awful lot about Python. Um hopefully it's not gonna play any sign line when I open it up. Um and I have streamed about GraphQL. You can see there's a bunch of stuff here. uh webhooks and real-time applications, mostly Python things. I have streamed in the past with Patrick about uh GraphQL. I hope to stream
Speaker 1: about it again in the future with him. Um I'm very interested in in subs the fact you can subscribe to updates. Because one of the things I didn't point out during this is the moment the reason that we're getting updates in real time in the front end is that it is polling. Not great. So there is definitely areas of improvement. Um and I know this has been very Quick introduction, as the description said. So I'm probably gonna keep building on this tutorial code on my stream Please join me there. You can follow me on uh Twitch to be notified when I'm live, or follow me on Twitter. I always post when I'm going live on there. But yeah, um that's been my slightly over 15 minutes introduction to GraphQL. Sorry, React, Raphael, and Django.
Speaker 1: I said I will be sticking around for questions. Um, I don't know if I still have our hosts in my ear. Are they here on Zoom? I don't know how we end this night, but um Yeah, I don't have anybody else there Well I think we're gonna keep talking then on until our Jack McConnell poster is back because I'm not sure if I'm still streaming or not. And I don't want to leave you all with that air. So I'm gonna keep talking for a little bit. I might go like check out this form thing and see what's going on on it. So I'm sorry if
Speaker 1: Hey, we're in post production both Smith Aye. Uh so I'm I'm gonna hang out the Zoom call because I'm not sure if I'm still broadcasting or not. Hello
Speaker 2: Hello.
Speaker 1: Hi folks.
Speaker 3: Why are you awake, Aaron? That's my question.
Speaker 1: Why am I awake? That's a very good question. Copious amounts of caffeine, huge amounts of caffe I actually I didn't sleep last night. I was just like, it is but once you're doing one of these kind of things, you always need a couple hours prep time ahead of stuff just to like run through it a couple of times, make sure it's familiar in your head, make sure your all your demos work and All that kind of stuff. So it's like I'm gonna have to get up at one o'clock in the morning. There is no point going to bed. So I slept a little bit late this morning. My my partner was very kind and took care of the dogs for me, let me have a lie-in, and yeah, and I've just been drinking copious amounts of this incredibly bad for me prepackaged l like Starbucks.
Speaker 1: Um yeah. It's it's weird being jet lagged without having flown anywhere.
Speaker 3: You're an absolute madman. Thank you for your presentation.
Speaker 1: Not a problem. I hope I know it was really quick. I hope people got something out of it. Um I'm sure you've got questions. So oh, there's a little chat button. Which one we prefer, the industry-based product, strawberry, or graphene. So strawberry is the only one I've worked with really myself so far. Um So mostly because I I was very lucky to have Patrick come on the stream with me and uh kind of explain strawberry to me a little bit and show me it. Uh that was really my first introduction to to GraphQL and obviously Patrick being one of the creator off Strawberry, that's the one that he was going to use. And honestly, I I've been really, really impressed with it. Like it's was so straightforward to get started with. There is a lot of plugins and things for it as well that remove some of the boilerplate that I'm screening there
Speaker 1: to make things like doing pagination and and authentication and and stuff like that easier. I just didn't want to I wanted to show them more of a low level of this than than just have a package that was doing all kind of you know magically in the background for me. But yeah, I would recommend there's a couple of more talks in at this conference, including one from Patrick about GraphQL and Django. So I would definitely check those out. They're probably going to go into a bit more detail than what I have. So coming from a DRF setup in production, how are we recommending transitioning into strawberry? What would be the equivalent permissions when using strawberry? You can do authentication of things that that other package is talking about
Speaker 1: has kind of helpers for that uh to allow you to to do authenticated requests. As you saw, when I was writing the resolvers, the logic in them is really up to me. You know, so I I can add my different permissions checks and stuff in there if I wanted to as well Moving from Django Rest framework to Strawberry, uh what I would probably recommend, to be honest, uh, is the two of them can run side by side pretty pretty easily. There's nothing preventing you from actually having, you know. So you don't need to do a what was the phrase? There's you know it doesn't need to be a revolution, it could be an evolution. You know, so you you can still have your your DRF uh endpoints there and then you can start replacing some of them with strawberry or running strawberry alongside of them and as you create new client applications
Speaker 1: or you know for new functionality uh on your site and you can start Moving those across the strawberry. So it's a single API endpoint. It's not as if you'd be conflicting with your existing REST API endpoints. You just have a new like GraphQL or whatever you wanted to call it endpoint that you're running your queries against. So there would be nothing preventing you from from having both running simultaneously on the same Django project while you started to port them across. And then so as you're adding new functionality or as you're refactoring things, you can move some across to Strawberry. Where I see the big advantages is if you have multiple different clients that are creating the same project, but each of the clients has different information that it requires. You know, you may have a iOS app, you might have the web website itself, you might have
Speaker 1: You know, uh your desktop application, each of them have different views, require different levels of information. They can now operate really independently from each other. You know, as I said, if if you need to add fields to your model, it's not gonna you don't need to worry about a knock-on effect with your different clients because they're only requesting the exact data that they need. Um it's only if you're removing fields and things like that that things can get complicated. As they would with any other API. And is Ras and General 9 moving into the realm of legacy technology? I don't think so. I had to use an API just a couple weeks ago that still uses SOAP. So old technologies are are still here. They're gonna exist for a while.
Speaker 1: I think REST definitely still has its place. One of the things I didn't touch upon in this is like doing file uploads, you know, not That's very new. There is support for it in Line Strawberry, etc. But yeah, there's definitely going to be areas where you know more traditional APIs are still going to be beneficial. But And so where I see the advantage of this is definitely with those multiple different clients with slightly different data needs and the ability to write resolvers that can span across multiple different models. area where you're making individual requests for e for each object essentially. You can bundle them together and serve it all as as one um object to the to the client.
Speaker 1: Can you please describe about Cookie Cutter Django? Sure. So Cookie Cutter is a it's an excellent applic uh it's a it's written in Python itself. It uses Jinja uh templating and essentially you write these templates. Which uh you can store on an on GitHub. And then Cookie Cutter will download the template. It'll ask you a bunch of questions You know, and you define what those questions are, and then it will use your answers to those questions in the templates. So basically runs it for Jinja and does some variable substitution on your answers into the templates themselves. So the cookie cutter Django Is a kick-cutter template for Django that has a bunch of different presets and a lot of the boilerplate taken care of for you.
Speaker 1: And it's it's from uh Pydani who uh is one of the authors of TwoSkips Django. It's actually Paidani has written the Django template for Cookie Cutter, and Paidani's partner, Audrey, wrote Cookie Cutter itself. So uh it's a really a a great team team up there. But it follows a lot of if you've read TwoScripts Django or you're aware of Tusclip's Django, it follows a lot of their best practices and it will do everything from set up your Django application to be used with Docker or Heroku. to configuring it to be used with different uh uh you know uh SMS or sorry not SMS sorry uh SMTP servers you know for sending transactional emails right for a free to White noise for serving up images or it has presets I think for like S3
Speaker 1: and does a lot of configuration. I think it even configures salary for you as well. So It asks you a bunch of questions at the start and then configures a lot of the Django stuff that you all we all have to do every time we're starting a new project. Personally like it for these kind of demos where I need like a custom user model, etc. But bearing in mind it will add a lot of complexity to your Django application. Like there's a lot of things that it does that you may not need it to start. It's great if you're thinking about like You know something that's going to be going into production very quickly, um, but it will add complexity. There is no doubt about that. It saves you an awful lot of time.
Speaker 1: but at the expense of making your project more complex. It's complexity that you probably will need, you know, setting up things like salary, etc. if you're You probably will need these things in the future, but it's completely now for things you may need in the future a lot of the time. So there is a trade-off there, but it's it's still fantastic uh template. There's a few other different ones Some of them will set up set up your Django project with React and everything as well for you too. I would just look to do the Cookie Cutter website itself lists a bunch of the user-generate or user-created templates. But also you can just search for them like cookie cutter, Django templates, etc. and find a bunch of other ones. Do you know if GraphQL works with WebSockets?
Speaker 1: So that is the part I kind of touched on a little bit at the end that GraphQL has this ability to have subscriptions where you can subscribe to changes rather than polling. I'm think it's over WebSockets, but I'm not sure. Uh the subscriptions part is when you I think fairly recently been um added to strawberry. It's something I know Patrick did a talk about at the Django London meetup um recently. I was um unfortunately able to catch it, time zone things. Uh but hopefully he's going to give that talk again someplace where it'll be recorded. Um and we'll get some more information about subscriptions then. What about select rated, prefetch related when you can freely include or exclude model attributes at runtime? Um how do you know where to apply joins, etc.
Speaker 1: ? Same way as you were doing any kind of view. So if you're creating your your regular class-based views to generate a template, you need to supply information to the context for that template renderer. Your resolvers are essentially the same kind of thing. You know, so you get to make that decision about how much information that you uh request and how much information you're providing. And then your Type obviously your types and can specify which parts of that to return uh over the wire to the client. Um how should we think about caching in GraphQL? Oh ,
Speaker 2: Mathilde, actually hello, follow up to this question because uh the question before my question. Uh hello. Um first of all, thank you for the great presentation. Uh I was actually asking about um whether you can uh decide or whether uh Django can decide uh if you need to select related some fields that are in the end not accessed by the client because uh uh they they are not asked by the client so so do you do you need to um query more data than you actually return all the time or can you differentiate it Thanks.
Speaker 1: Yeah, so in your so you mean like in the resolver, for example, if you had the the products being returned, but the person hasn't requested any fields in the products, would you need to fetch all the products? I'm not sure. Um that's a good question and I probably will need to ask Patrick about it. Um But yeah, I don't know off the top of my head if it's if it's smart enough to see that that hasn't been requested and then um not execute that part. Or if you can check In your resolver to see what fields have been requested, and then you would be able to write some applic some logic in the resolver yourself. I'm not sure. I I would like to think so. Um but I I'm only hazarding a guess um at the moment. I would need to go check the the extra resolver logic for those to see if there's an ability to to check for the fields that have been requested.
Speaker 2: Okay, thank you.
Speaker 1: So how should we think about caching GraphQL? Should we only stick to ORM layer caching? So the GraphQL client that we saw there, um it does have caching so there was some client side caching already and that just comes built in. I was just using the in-memory cache there. For the uh caching on the server side um Really, honestly, it kind of I think this ties in a lot to what we were just talking about previously with you know the level of data that you're having to query and the access there. it it's gonna be the same kind of thing as your REG replication caching, and that's gonna be you're gonna decide that on almost a case by case basis, you know, um depending upon how fresh needed information to be, you know, doesn't need to be real
Speaker 1: time. And that could change depending upon the individual resolver that you're calling. You know, whereas you probably want order status to be 100% up to date. Um you probably don't need something like the weather in my in Florida. You know, if that's ten minutes out of D That's probably fine. You know, so all these kind of things is really gonna depend upon the freshness of the data that you require. And that's just gonna be that's just your regular kind of application caching, which I know is Pretty difficult at the best of times, but I don't think GraphQL makes that any easier or any harder Any Over questions
Speaker 1: Looks like we could be out of questions. I'm just having a quick look at the secondary room to see if anything came in. Oh, somebody's mentioned that there is no requirements text in the GitHub repo. I don't know if that person oh I see Daniel has answered already. Um I don't know if that 's uh person is in this chat, but for anybody else who couldn't find it, it is in the requirements folder in the RGD in the Django. uh directory um in the repository. All the requirements are in there and they are broken down into a local and a production, um which again is just something that came with Jungle Cookie Cutter, um I would always see if you're just installing it to play around with, probably install a local version.
Speaker 1: Um And I think that's all the questions. So thank you for joining me, everybody. I'm probably gonna be alight of this now, and hopefully I will be awake enough to hang around and see some of our talks. And I'll still be hanging about in this Slack for a little bit. So if anybody does think of anything, you know, hit me up there. Or if I'm gone, please feel free to message me on Twitter. It's probably the easiest way to get hold of me. Okay, Jerossier Conference folks. Thanks again.
Define Strawberry types that represent the data you want to expose, write resolvers to fetch and transform Django model data, combine the resolvers in a schema, and mount that schema on a Django URL using Strawberry’s GraphQL view.
Discussed at 9:25A resolver can load related Django objects and map them into a custom GraphQL type. In the example, an order combines cart, address, user, and product data, while the resolver calculates a total that does not exist on any single model.
Discussed at 11:45GraphQL lets the client request only the fields it needs instead of receiving a fixed, complete REST representation. This reduces unnecessary data transfer and means adding fields to the API does not unexpectedly change what the frontend renders.
Discussed at 17:59Define an input type, write a resolver that receives the object ID and input and updates the Django model, then add the mutation to the schema. The example updates an order’s status and returns the updated order.
Discussed at 21:58Run the React and Django apps on their separate development ports, configure Django CORS headers to permit the frontend origin, and use React’s proxy setting so API requests can be forwarded to Django.
Discussed at 33:48Create an Apollo client and provide it to the React component tree, then run a GraphQL query from a component. Apollo exposes loading, error, and returned data states so the component can show a loader and render the results when the query completes.
Discussed at 38:31Note: 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 June 13, 2025
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025