 So recording is running. All right, OK. So I come back, part two, the front end. So so far, basically, what I wanted to show in part one is creating a Django application is really easy. You just do Django admin start project, and then Django admin start app. And you write your first model. Then for each model, you will have to write a type, a Django object type. And then your API is essentially a collection of mutations and queries. And those are essentially just functions and which are also very easy to test. So that's all we've done on the back end. And we will come back to the back end later for a little bit. But most of the stuff that I'll cover now is quantum related. OK, so when you have a GraphQL API, it's not so easy to consume. It's not like a REST API where you can use curl and you send curl requests. And you get back nice JSON responses. Building these requests for GraphQL is a little bit more complicated. I mean, just look at, when I write the query here, write in the editor and execute it, this is like a request here in my URL. It's like, yeah, you won't probably do that in a curl request, right? So let's create a new React application. What you would do is you would npm install create React app. It's a wonderful project from Facebook that kick-starts a new React application. When you run that, you have to give it a name. So just like we call our back end, back end, we will call our front end, front end, because we are super creative. And when you run create React app, front end, it generates this front end folder and right away, you should be able to run Yarns. Duh! What's that? Oh, the front end folder is actually empty. Why is that? Okay. It's not empty. What the hell? Ah, okay. Wow. I think I was still in that folder, but I deleted that folder and then my terminal was somewhere in Nirvana. So this is what you see right after you created a new React application. And the first thing that we wanna do is we wanna add React Router to the mix. Every modern React application probably has React Router, so you would do yarn add React Router DOM, just installs React Router, and then so the main file that create React app installs creates is this app.js file. This is essentially what we see here. App.js file is this file. So we will replace that with something more fancy. And you can see that I am basically just importing a few things from React Router, and then all the views that our application should have. Those files obviously don't exist right now, so I need to create a views folder and then we're gonna have a list view and we're gonna have a create view, detail view, log in view, and finally we're gonna have a logout view. Those should be all, yeah. Okay, this will obviously still crash because there's no code in these view files. They all look in the beginning. Let's just put some dummy code into it. So now all the imports here should be correct and our app is, the cool thing about create React app is that it has a really powerful webpack config which hot reloading and stuff already configured. So while I'm typing, it keeps reloading and while I'm saving those files and every time I go back here to the browser, you will see that it suddenly looks different than before. So we should now be able to click at all these links and it renders different views, okay? Okay, little React Router crash course. So it was like this, we import browser router and we give it an alias called router and we wrap our entire application in that router component, okay? And this is basically just the bunch of links that we are having here. Instead of A-Tags, the HTML link, I'm using React Routers link. So because if we would use A-Tags and you click at it, it's gonna be a page refresh. But if you use the React Router link, it will use the browser history push to just change the URL but not really reload the page. So you can see that the URL is changing. I can even use the back button but React Router kind of takes control of my URL. And then we use the route here to say whenever the URL is home, like just slash, we render the list view component. If the URL is logged in, we render the login view component and so on, okay? You could even do something like this if you remove the exact here. I believe when we go to log in, yeah. See, now every URL starts with slash. So this will always be true. So now it's rendering the list view no matter where I am and whatever other view I am at. So now I'm seeing both of you. So this is like a little bit, if you come from Django, thinking about routes like this is a little bit confusing. It's not like your URL's file, even though it feels like it in the beginning. It really just switches on or off the rendering of certain components based on your current URL, okay? I might even have more components deeper down and I just put more routes in there and these things will only be shown if the URL is a certain URL. It's quite interesting to build applications like that. And here we have one route which has a dynamic part. So whatever is gonna be here in the ID, this is the detail view, right? So if I put a number here, this is gonna be my ID. And this ID will be available as a variable inside the detail view and the variable will be called ID. You will see that later. Okay. So now everybody is a professional React route user, right? Pretty simple. Now we wanna use, finally, you wanna use Apollo React. So you will do yarn at React Apollo and once again, we have to do a few things in our main application file. So we have to import a bunch of stuff that comes with Apollo. And then we have to do, you know, when you go to the Apollo docs, they will basically immediately tell you to do this stuff. You don't really have to understand this. The important thing here is we are telling Apollo where our GraphQL API endpoint is, okay? This thing here means that if your application is quickly generating tons and tons of requests, they will all be put into a queue and every 10 milliseconds of Apollo will grab the entire queue and merge it to one query and send only one request to the server. So that's quite cool. And this is for, you can add custom HTTP headers here. So here, if you would have a session-based authentication, like you have a normal Django website and people are logging in and it's a cookie-based application, you could do credentials include and if the user is logged in because of the cookie, the cookie would be sent and in your GraphQL views, you would already be authenticated and request.user would be available. But this front end here is not cookie-based. We will use JSON web token. And then you have to wrap your entire application in between this Apollo higher order component providing the client that we just created. So setting up Apollo is really easy. Nothing much that can go wrong and even if you already have a very complicated react front end that you might already be using, it's not interfering with anything else in your application. You can just wrap it around everything. It has its own Redux store that doesn't interfere with your own possibly already existing Redux store. And so I think this is something you could just add that to your application and then even if just one component uses GraphQL and everything else still uses a REST API, you can start using it like this. You can slowly migrate away from REST APIs towards GraphQL endpoints by just doing it one endpoint at a time, one component at a time on the back end of front end. Okay, so let's see if our Apollo installation worked and let's try to query some stuff from our database. So we wanna see something on the list view here. So I open up the list view, yep, it works. I'm getting stuff from my database. So let's try to understand what's happening here. If you want, okay, first of all, not everybody has used React.js. So this will be very confusing. In React, basically, you build components. Everything that you can see on the screen is supposed to be a component, okay? So when you look at the entire application, for people who have done websites before, this looks kind of familiar. This is HTML syntax, right? There's a div here, there's a UL, there's an LI element and so on. But there's also stuff that is not normal HTML, like the route component here. And so this is a component that somebody else has written. And then the same thing, in the same way, we will write our own list view component, right? We could hook up the list view component like this. Like it looks like an HTML component and whatever is in this component, like whatever is in the render function here, this HTML markup would be rendered at this position. That's the idea of React.js. Like small components and then you keep moving them as if they were normal HTML components, right? So our list view is just a div. And it's just a bunch of paragraph text that have links and the names of the messages, right? So it's essentially what we can see here. One paragraph, one paragraph, and these are all links and you can click into them, okay? So the magic that GraphQL allows us to do is we can import GQL and GraphQL from React Apollo and we can define our query right there in this file where we are also writing a component. So this is like this powerful thing that React.js allows you to do. You have your styles right there in JavaScript, right next to your component. This is something that a lot of people are like, oh my God, separation of concerns. We have been writing style sheets for a decade. Why are we doing it in one file again, right? But it turns out it's actually very good because if your boss tells you, this button has some pixel errors, like the padding is not big enough and whatever. As the developer, you go to button.js and you see the styles right there and you fix them right there and you know you will only affect this button and nothing else in my application. Whereas when you change some styles in your style sheet most of the time you mess up something else on the other end of the website. And now we can also do this. We can not only put the styles next to the component, we can put the query, the data that this component needs right next to the component, right? The list view needs the list of objects, of messages from our database. So why not put it right here? The programmer doesn't even understand SQL but they do understand how to write a GraphQL query, right? So the front-end developer, it can be a designer. It doesn't even have to be a real developer. I mean, everybody's engineered in some way, right? It doesn't even have to be somebody who studied information technology or something like or computer science. This is something anyone can understand. So we put it right here. We say we want to get all messages and we want to get the IDs and the actual text. We need the IDs in order to compute, produce the links, right? We have to link to that ID, to this new URL here. And of course we want to see the message text, right? So we have our query. We have our component and here we need to do, so we import a GraphQL here. This is like a decorator, so wrapper function. So we pass in our query, this variable, into our wrapper function and then we wrap our component in that wrapper function. And this makes sure that our list view now has some additional magic that it usually wouldn't have. And this is, you can now access the variable, this.trops, this everywhere component has this.trops, but now we have this.trops.data. This comes from Apollo. This is the GraphQL data that the component might or might not have, okay? When the component gets mounted, it immediately tries to execute this query, so all messages. And this.trops.data.loading will become true, okay? So while it's loading, you might just want to return some generic representation of your component that doesn't need any data. Like when you imagine how Facebook does the home, so see, it's still loading. It renders two components that are just great. You don't need any data for that. This is just graphics, it's just fancy stuff. But see, every time, while it's still loading, it's showing us something that you can just design. You don't need data for that at that moment. So we do the same, we just render loading here, but once loading is no longer true and we actually got some messages back, we will render our real list, okay? And yeah, we will just iterate. So, and then we will have this.trops.data.allMessages, the name of the endpoint, okay? And each message will have .id and .net, exactly those fields that we have requested, okay? And this is another important thing about GraphQL, which makes it more superior than REST API endpoints. Imagine like, for example, for my own startup, I have a product list view here. The endpoint that returns a list of all my products has like 50 or 60 different fields. Our product model has tons and tons of information. And I'm showing, I don't know, 60 products here. And I have all these fields. I have to send them over the wires called bandwidth, right? With GraphQL, it only sends exactly these two fields, the ones that I requested. Getting this done with REST endpoint is pretty hard. You usually get all the fields, right? And waste a lot of kilobytes of bandwidth. So yeah, so that's it. That's how you build your components, right? You generate your markup. You build the query and then you use the data from that query in your markup, right? And you wait for the data to load first. So, you know, when I used REST APIs before with GraphQL, with React.js already, I was using Redux and then I was doing patch requests. And I was always observing my Redux store if the request came back and so on. All gone. All this boilerplate is gone. I literally have no Redux store, no action creators, no actions anymore, no reducers. I only have this query, that's it. And, you know, this decorator down here. So yeah, once you've seen this, you really don't want to go back anymore. Okay, so this is, so we just tested that our Apollo installation actually works. So we can see some data here, right? So next step, let's try to do the detail view. Hopefully, yeah, I can go into the detail view now. That's true and so on. So what's happening here? Same thing. I'm first checking if it's still loading, if it's actually there, I'm rendering my actual view. Now we have this.probs.data.message. It's always the name of the endpoint that will be available in your component. And so, and then exactly the fields that I actually requested. So I can access.message.ideen.creationdate.message. And render them on this screen, okay? So this query is a bit different. This query, you see, it looks different. We haven't seen this today. It's a named query. So I usually give this the same name as the view. Or you can call it detail view query. It's really up to you. I haven't come up with a good best practice yet. So I just give it the same name as the view. And this query needs an input value, right? When we think back to our schema, simple app schema, we said that there is an endpoint called message and it needs an ID as an input parameter. So in our resolver function, we can take that ID and then query that primary query from our database. Okay, so the schema already knows that an ID is required and it forces us to provide that ID. This exclamation mark here also means that we have a name query that has a variable called ID and this type ID and it's a mandatory variable. To try to execute this query without passing in the ID variable, it will crash. And the best thing about this is, it's already great that I have the query in the same file where my component is, right? As a developer, I will try out these queries in the graphical endpoint, right? I might not even know what endpoints are available. I'll just use the autocomplete. And you will basically, I'm most of the time just pressing on both face all the time and the queries, they kind of build themselves. I don't really have to decide anything. If you have a query like this, when you say it needs variables, you can define those variables down here. You work in GraphQL, you figure out the query, you copy and paste it into your component and then you start using the database. Okay, but now there's a difference. We have to be read, we pass in our query into the pass in query option. These have to be the same name as, but we need dynamic values. So just, many people are, when this component mounts, it already has this ID variable from React Router. So it can automatically generate this, fill this query option. So this query can actually be executed when the component, so this is how queries with dynamic parts, queries that need to have. So the first, the list view was an example of just a query without any variable. And the detail view was an example of a named query that requires input value. And then you need to create this query option here. Okay, so the last view was to create you, but you have to be authenticated before you can write messages into the database. So we need to do a little bit of magic now. So now on backend, back in Django, I create a middleware. So in the beginning of my talk, I said that I dismissed the GraphQL hosting and the PyWT Python wrapper around DWT. I used the REST framework, JWT implementation because it's already used by a large community, and I think it's well tested. So I create a middleware that tries to see if there is an authorization HTTP header on the request. And if yes, it passes the request into this JWT authenticated function that someone else has written. So I don't know what's going on in this class. I'm just instantiating that class and I'm passing in my request. Either the authentication will fail. In that case, I'm done with my middleware. I just call the next middleware. Or I actually got back the authenticated user and then I attach that user to the request. Okay? Because that has the effect that in my, like for example, I always told you that context here in my resolver functions or in my mutate functions is essentially the general request because of my middleware, context.user will either exist or it won't exist. Okay? So this middleware always tries to see if there's a token in the HTTP header and then try to see if that token is valid. And if it's valid, it will get the user from the database and attach it to the request. And oh yeah, in order for this middleware to work, we have to add it. Basically, you know, when a request comes in and Django is catching the request, the first thing that happens is the request will travel through all these middlewares. And they are basically all just functions that might manipulate the request in some way. They might add more things to the request. For example, here is where request.session gets added to the request. If you are using a cookie-based authentication, here is where request.user gets added to the request if you are authenticated with the cookie already, right? So basically the request travels through all these middlewares. So it will eventually travel through this function as well and we might add the user to the request. And then later, everywhere else in our Mute and GraphQL functions, we can access this user field on our request object. Oh yeah, I'm a bit lazy here. I should actually create a new app called user profile. But I don't want to have too many apps and colas, so give me a second, I will explain what I'm doing here. So I import the built-in user model from Django and I create another type, just like we had our message type. We also have a user type now. And then we will add a new endpoint. As I keep saying, they come in pairs, the endpoint has a name and it has a result, always the same. So we have an endpoint that returns the current user. If you are locked in, it actually returns your user. If you are not locked in, it just returns line, okay? So let's try if this works, I'm locked in because I'm locked in into the Django admin and here at port 8,000, I actually have a cookie-based authentication. So since I'm locked in, I have a cookie to have a few things that I'm locked in. And the cool thing is, see this? These are all the fields that the Django user model has. First name, last name, email, it's that and so on. I didn't have to write any code for that. I basically only wrote these three lines of code and all the introspection and serialization and stuff happens magically already. Really powerful. Okay, so now we have, okay, this Apollo also has the notion of middlewares. We have our network interface variable here and we can use network interface.use and then apply batch middleware. This is a function, I think. And here I'm trying to see if the token is currently safe in the local storage of the browser. If yes, we attach this text JWT and then the token that we might have found to the HTTP headers, the authorization header. Right? When we look back at the middleware, this is exactly the HTTP authorization header. You know, when the request comes and Django does a lot of stuff for it. So it's named a little bit differently. But in here, I would expect JWT, blah, blah, blah and the long token. If I can find it, I will try to authenticate the user. Okay? So we now have a middleware that searches for the token and every single GraphQL request tries to attach the token for the request header as well if it's available in the local storage. Okay? Of course, currently it will never be in the local storage because we don't have a log in view yet. Now hopefully everything will make sense. So this is why I built the current user endpoint. I have a create view, right? And the create view should not allow me to see it if I'm not not fancy. I'm going into the create view and it kicks me out and pushes me to the log in view instead. I can see all the other views but I cannot see the create view. Okay? And one way how you can implement that is you simply, when the component gets mounted, you request the current user. And we have designed this endpoint that it either requests the current user or none. Right? So, you know, we wrap this view in that query and then on component will update. So this is a lifecycle function of ReactJS. If you're not familiar with ReactJS, just ignore this. So this function will eventually get called every time when the properties change. So at first, for example, data.loading is false. Then the component mounts and the GraphQL query will be sent. Then data.loading will become true. So the component re-renders itself because one property has changed, right? Every time any property changes, this function gets called and the render function also gets called again and the component re-renders itself. So we checked if it's no longer loading and if we have data.currentUser from our query available and if that user is null, if the response was null, means we are not logged in, then we use window location replace to forward to the locking. Okay? So this is a way how you could protect your views from unauthenticated people. You probably don't want to implement this in every single component. So you might create a higher order component and then you might do something like this, log in required. Every view, you will wrap it in log in required and then this component, this log in required component implement this only once, something like that. So there are still some best practices that I also figured out. All right, so we have that. So okay, we still can't really create messages because we are not able to log in. So let's implement our log in view and this will be an example how to, oh yeah, how to store the token and load the storage, okay? So let's do the work. So we pick a create message, it bounces across to the login view, we log in. Okay, so what does this view do? First, let's read it from bottom to top. The view is a normal HTML form and it has an input element for the username and password and it has a submit button, right? And every time when the form is submitted, so either you click the button or you press enter, we have a handler function here. First of all, we prevent what the browser would usually do. You know, if you have U of J query before a JavaScript to prevent default, it's a good way to stop this event from doing anything else because otherwise when you press enter or you click the button, the page will try to do a post request and submit the form or get request and this will cause a page reload and we don't want that. So we stop this event. This form data API is something that modern browsers support. If you give this a form, it will have all the data, all the fields, the fields and values inside some strange object. The fetch API is something that modern browsers support. I mean, if you build something for not so modern browsers, you would have to, in your main entry point file, you would have to import Holyfields so that like Internet Explorer doesn't support fetch, I think, so that these browsers still work with your application, right? So we use fetch. We can't use GraphQL here, right? Remember our JWT authentication endpoints, these three endpoints, for get token, verify token and renew token, they are normal rest endpoints. So we can't use GraphQL. So we just sent a normal HTTP request as a post request and the body of the request is the form data, our username and password, all right? This is a promise. So we use dot then, and this is the result that we get back from the server when the promise results. We know that because of Django REST framework, all the responses are JSON strings. So we can call the JSON function and then we have our JSON response and if we successfully authenticate it, there will be a queue called token in the JSON response. Actually, do I still have this open? This is the JSON response that we will get back when we try to authenticate. There's a key called token and then the token is the actual value, right? So and then we call local storage set item. So if we got the token, we put it right into local storage and then I like to reload the window. I mean, you don't really need to do that. You probably want to redirect to some other page after the user has logged in, like redirect to profile or something. Usually when somebody logged in, a lot of stuff had changes on the front end and I just like to refresh the entire page. All components try to patch their data again. This time they are locked in so they might get slightly different data. I just like the clean flush of my store. So I just do a page reload. So let's try that. We go to login. Oh, I should have just said already, right? So that's a page reload and now I'm locked in so the create you doesn't kick me out anymore. When I go into the create you, it tries to patch the current user and this time it's not null so the view will not bounce me out and it will render itself. So this is a simple way how you could deal with authentication in a GraphGL and React.js stack, right? Since we are at it, let's also go to log out view. Very simple. All it does is it deletes the token from local storage, remove item with this key and then do a refresh, right? Once we do a refresh, all GraphGL queries will be sent again. This time we are no longer indicated so we will get different data. And this is actually getting close to the end. So our create view was smart enough to bounce us out if we are not logged in. Now we want to make it smart enough to actually create items for us. Log in. So now I have a form here. So let's look at the markup first. Same thing. Normal HTML form has a text area, has a button, has a submit handler. So when you click the button or you press enter, the submit handler will be fired. So what does the submit handler do? Prevents the normal form submit, fetches the data of all the input fields and then it calls this.props.mutate. Why is that possible? So let's look at this first. We already have this query here to get the logged in user to know if the user is allowed to see this view or not, right? Now we add another variable called mutation and we put a mutation here. Mutations are always named. So I give it the same name as the create view. And this mutation needs an input value called message. You might remember when we built this mutation here's the class. There's the subclass input and we said this mutation needs a message. When you want to write a message you have to submit the message obviously, right? So because this field is here, we must provide this message when we call the create message endpoint, okay? So we create a mutation that requires a variable and we use the variable here and we also know what kind of return values the mutation provides either by looking at your schema, our return values are here. You might remember these or by simply trying it out in the editor, right? I can say mutation, create message, okay? It needs a message, blah, and it has these return values. So you don't have to look into your code. You can just use the graphical editor and you should and you will. So what else does this thing do? So we know already how to attach a query to our component and attaching the mutation to your component that works in exactly the same way. You use the wrapper function and now you put the mutation in and you wrap your view around it. So you can actually wrap your view several times, okay? And when you do this, when you wrap your view inside the mutation, you now have available this.props.mutate, okay? We know that this mutation needs variables. So we have to pass in a JavaScript object with those variables. So that's the value from our message field. And this is also a promise. So when the promise results, we get our result and we know that the result has status form errors and so on. So we check if the status is 200 and then we just go back to the home view and hopefully we can see our newly created message. So let's try that. Thing and here it is. All right, so it seems to work. Great. So next thing that is a very common thing is how to handle form errors. I used to do this in Redux stores. I used to keep track of my fetch requests coming back. If there are form errors, I put them in a Redux store and then I pass, I have like form error components down here where I pass in all the errors from my Redux store, something like that. But I think with GraphQL, since I'm not really using Redux anymore, I will simply keep the form errors of each view in the view state itself. That is actually quite good because when I put my form errors into the Redux store, I often had the problem that I went back into some other view and then I went back into the view that had form errors and the data was still sitting there in Redux and all the form errors were still showing although the form might be empty now and the user still sees the old form errors from last time. So I had to do a lot of housekeeping to make sure that I remove my form errors when they are no longer relevant and so on. If you just put these form errors into the component state, when the component gets unmounted and then remounted, the state is also empty again. So the housekeeping happens naturally by itself. So we will initiate the state and say, by default, there are no form errors, okay? Then we will change our submit handle a little bit. So now we say when the response comes back from our mutation, we check if REST data create message status is 200. So in that case, no form errors. We just go back to the home view and we can see our new message, right? But if REST data create message status is 400, so you know this data create message status, this is the return value from our mutation here. So if that's 400, that means there were form errors. That also means that create message dot form errors is a JSON string, right? Because we designed our mutation so that whenever there's an error, we return a JSON string here in Django. So then we call this dot set state. And so React works in that way, whenever any property changes, or whenever the state changes, the render function gets called again. The whole component re-renders itself, right? So we will now have the option to put something like this below our text area. So we say, if in the state there are form errors, because at the beginning it's null, right? There's, it's not a JavaScript object yet. So if it's no longer null, and if there is a form error with the key message, then we want to render a paragraph with the actual error. Okay, so let's try it. The JWT token by default is configured to expire every five minutes. So that's why I have to keep logging in. You can actually configure that and give it a much longer time range. So yeah, if I put an empty message here, I'm getting a form error, okay? I mean, you don't really want to write this much code for each of your input fields. So you would probably create a form error component and then put in all the errors and maybe the name of the field. And then this component will have some logic to check if there are errors and if there's the same field name error, then render this text, right? Whoops, so yeah. Okay, I think, so how much do we have left? Filtering and pagination, so just two more things. And those are the most confusing, complicated things. So Graphene Django is tightly integrated with something called Django Filter. So Django Filter is another very well known plug-in for Django that helps you with filtering your queries, your database queries. And Graphene is also integrated with that in some magical way. So all we need to do is on our message type, say something like this. So we want to be able to not just get all messages, we want to be able to get a few messages and only those where the message column in our database contains a certain substring. So it's like a full text search, okay? This might make more sense when we see it in action. And then all we have to do is we have to define which fields of our model are filterable and we have to change this endpoint here. It's no longer just a simple list, it's now this magic Django Filter connection field. So just take it for granted. It should work. You can try to run a query like this. Whoops, okay. So I think I had, I think all my, oh, I have some with ASD, right? Yeah, so the filtering seems to work, okay? Problem is, not problem, but you might, if you are like still super awake and you might realize that we have this edges and node thing here suddenly. That wasn't there before. I don't fully understand why this happens. I think this is also some GraphQL thing. Actually this will make more sense when we come to the last chapter after this about pagination. Then we will see why having edges and node here is useful. Okay, so just like that means when we change our query like this, we have to update our front end as well, list view. So I put the updated query here. Before this was just a query without variables, okay? Now it's a named query which has one variable, the search string. And when we have a named query, we need to have query options at the bottom of the file. So I have my query options here. I know that my variable is called search. And I know that React Router gives me access to this props.location.search. So if we have something like this, search equals something. This question mark search equals full. This string here will be in props location search, okay? Then I installed a little helper function called query string which turns this string question mark search equals full into a JavaScript object with the key search and the value full, okay? And since I now know that this is a JavaScript object, I can access the key search which is this key, okay? So this becomes the value for my variable. So no, now when this component mounts, it tries to execute this query. And this is not a mandatory variable here. So no question, no exclamation mark here. So this can also be empty. And if we query with an empty search, we get all objects, okay? But if we change the URL to question mark search something and this component mounts, it will take that value from the URL and execute the query with this new string, okay? Then I added a form here with the search fields and a submit button, okay? So this looks like this. And when the submit handler, when you submit the form, the submit handler simply uses react routers, this.props.history.push and it pushes to this same URL, but it adds question mark search equals something to the URL, okay? So this is like a nice pattern. Your form controls the URL, right? When I type in something here, the URL changes, okay? That is when you submit the form, you change the URL using this props history push from react router. But when we change the URL, thanks to react router, it means the properties of this component have changed, right? This.props.location.search is properties of my component. The search has now changed. So the component re-renders, okay? If the component re-renders, it realizes that the variables of my query have changed. And that means it sends the query again and we get back new data that we can render. So by manipulating the URL, the component re-renders itself, it sends the graph query again with the new variable and we will get back a different result. So we can search for two, we can search for test, we can search for ASD or for nothing, okay? So this is how you could do filtering in your application. And finally, so happy that nobody fell asleep yet. So pagination, this is really tricky. But it's the last thing for today and lots of people asked me how to do this. So I just wanna show it. If you don't get it, look at it when you have more time at home. What we wanna do now is we wanna have this kind of endless scrolling, you know? You have a list, product list, hundreds, thousands of products, you show the first 100 and when the person reaches the end of the page, you show the next 100 and so on. So it's like this, I press load more, load more and I get. And then when there are no more, the button also disappears, right? So this is how simple pagination could look like. And Graphene has something called cursor-based pagination kind of built in already. So, and because in our schema, we are now using this Django filter connection field, it kind of supports this cursor-based pagination as well already and that's why suddenly we have this edges and nodes thing here. It has something more. It also has something called page info which has next page, has previous page, start cursor and end cursor, okay? Let's just try to use them all and then maybe I filter for nothing so I get all of them. So obviously I just queried everything so there is no next page and no last page and essentially the start cursor should, I'm not sure how to interpret the cursor actually. I thought it would be the idea of these products but it's really something else. It's probably using Postgres features of having cursors for pagination somehow. I'm not sure. So, what we do now on the front end is we blow up our query even more. It's a name query. It was a name query before because of the search string, okay? Now we have another parameter that should go into the query and that is the end cursor and we change the query. We say we only want to have the first two items of the result set. We might filter maybe and we want to have the first two items after the end of my last cursor, okay? When the component mounts, we set this variable to null. That means we want to have the first few items after there is no cursor. So just give me the first two items of the entire result set, okay? But when we click the button, the load more button, we have this load more function. Here we can use something that comes with GraphQL. So we already know we have this props.data, right? GraphQL gives us that in all our components. And data has loading. We used that before. Data usually has the name of the endpoint and it's data if we already fetched some data and data has something called fetch more, okay? We can say fetch more of this same query. It's this variable here, right? Same query, we want to get more items. This time, we still key in the same variable from the URL, the search. But this time, we have the end cursor because when the component mounted at the very beginning, it executes this big query here, right? So the data that we get back includes all this, including an end cursor, right? So we can now use that end cursor from this props.data.allmessages, it's that one, .pageinfo, it's that one, .endcursor, right? It's that one. So this executes the query again, but it does not replace the data that comes back. There's another function called refetch. You could also say when you press the button, refetch this same query with new variables. But if we would do this, we will always see just two items, two different items, but the list will not grow longer and longer and longer because refetch replaces the old data with the new data, okay? But sometimes that's not what we wanna do. Sometimes we want to add more data to the end or the beginning or somewhere in between of our store. So I already mentioned like what is it? The end, the beginning, somewhere in between. Apollo doesn't know. You have to tell Apollo how to merge the new data with the old data. So that's why there is, when we call fetch more, we provide three things. We provide the query that needs to be fetched, the new variables for that query, and then an update query function that needs to be called once the new data is there. And this function has access to the last data and to the new data, okay? Then we would fetch from next fetch more result and then all messages edges. This is the new edges, the list of edges from the new data, okay? And we also select all messages.pageInfo from our new data. So we are like, see, from next, from the next variable, from the result, we take the new edges and the new page information. And then this update query function should return a JavaScript object that basically looks like the return value of this query should look like. So it would have all messages, edges, nodes, data, and page info, right? So we provide all messages and edges will become our last edges, right? Plus our new edges. It's a new list, the old values combined with the new values. And we completely overwrite the page info from last time with the new page info. There will be like haspreviews, hasnext, and the endcursor and startcursor will be completely new values. So we just replace that entire thing, okay? So, yeah, and with this little magic here, when we press the load more button, the new data will be appended to the end of the existing data. This all results in new props. So the component re-renders itself and it now renders the new list of data, okay? Which is longer than before and then it looks like new stuff is appearing at the end. And then, of course, we need to add the load more button here and we use the hasnext page information, right? From data, all messages, page info, hasnext page, which is exactly what we queried here, right? If it's true, we render the button. If it becomes false, the button just disappears, okay? So this is how you could do pagination. Eh, where's my, okay. Okay, and then the final topic, I mean, it's already a super long talk. I figured I won't have enough time anyways and I actually haven't really figured it out yet. There seems to be bugs in Apollo. There are some ways to, okay, oh, wait, wait. One thing I really need to show first and this is like another reason why all this is extremely worth doing. Let me shrink down the browser here. Apollo caches all your results for you automatically. So let's say I go, so when I first load my page, we can see one post request to our GraphQL endpoint, okay? When we go into this, we have never fetched this item. So another post request, right? When we go back, no more post requests. It can still show us the list from before from the cache, right? I go into the second one, sure, new post request, but now I can bounce around in my app and there are no more requests sent across the wire because all the data is already cached nicely in our, in Apollo's internal readout store, okay? Yeah, and then I can click at this, I can click at that. And I think from now on, everything should be in the cache, yeah. So this is like, if you build mobile apps, usually mobile apps are really wasteful with requests and this saves so much bandwidth. It's like, extremely worth doing. In GraphQL, you know, I didn't have to write a single line of code to get this feature out of the box. But of course, then the first question everybody asks us, how to deal with cache invalidation? What if I really want to get rid of that item from the cache? So I put some links here. Actually, some guy went ahead while the Apollo people are still discussing how to do it and created a possible solution, a nice API how to do this. I haven't tried this yet. There are some in, oh yeah, so, what is this? Oh, this is still the same. So Apollo has this thing, refetch queries. Usually you will have a mutation, right? You press a button somewhere in your UI, save some data to the database and that means some other places in your UI also need to update, okay? Maybe your number of friends on Facebook has increased by one because you followed that guy. So you need to refetch your friend's query after posting the, become friends mutations, right? So you would be able to do something like, when you call a mutation in the options, you call refetch queries and this can be a list of query names, right? I think these should be these query names. I tried that. I couldn't get it working. It always says, cannot find a query with that name. I believe it's a bug in Apollo. Maybe I need to upgrade to the latest version on master branch and it might work. I didn't have the time to try it out. So there is something in place already to, with quite little effort, update your cache when needed. The community is working on it. Yeah, but the stupidest solution would be if you have a view, for example, a product detail view. People are browsing around on your product grid. They click into a product and you always want this data to be fetched no matter what. It should never be cached. Then simply in your query options, you can say fetch policy network only and then it will never be put into the cache. It will always result in a GraphQL request. I mean, which is fine, right? I mean, when the user clicks around in your app, how much data is he possibly gonna, how many products is he possibly gonna tap at? It's not gonna be hundreds of thousands of requests. So in this case, like the typical marketplace app, whatever, where you have lots of products and when people click into a product, I guess it's okay to fetch this data every time somebody ends up here, okay? Yeah, okay, so that's basically everything I wanted to show today. So what we've done is to recap, we created a Django app. We created a model, a message model for that Django app and then we describe how our GraphQL schema looks like by saying, you know, our schema has this message type and our schema also have users and we describe what kind of endpoints we wanna have. Endpoints are essentially here. These are the names of our endpoints. For each endpoint, we have to write a resolver function that fetches the data from whatever database, right? This could be the normal Django ORM. This could be a MongoDB. This could be fetch request to Twitter API or whatever. You can fetch your data from anywhere. Mutations are its own class. They also have endpoints, but you know, it's a bit more complicated because you need input values. So once you have all this in place, you can start playing with your schema in the GraphQL editor. And you know, your developers, they will just look at this. What mutations are there? Create, okay, what does it return? Okay, it returns these three things. What is message? It's message type. Okay, it has user, what is in user? Oh, it's user type. Oh, it has all these fields. I mean, it's really awesome, right? Anyone can work with that without much prior knowledge. So onboarding new people in your organization will become super easy. You just tell them, here's GraphQL, have fun, right? And so that's the backend. And on the front end, basically we learned, simply import this, create a query right there at the component that needs the data, wrap the component in this wrapper function, and then have access to this.props.data.loading and the name of the endpoint that you called with all the fields that you called. And that's it. That's how you can use Django and ReactJS and Apollo and GraphQL. Thanks.