Client-Side GraphQL in React Client Side Schemas
Transcript from the "Client Side Schemas" Lesson
>> Scott Moss: The next thing I wanna talk about. So I mentioned something about managing local state with Apollo and GraphQL. And yeah, I wanna talk about that cuz I think it's really cool. And in order to learn about that you have to understand client side schemas. So, if you're taking any of the Apollo server side courses or the GraphQL server side courses that we have here, you already learned how to create schemas on the server side.
[00:00:23] If not, you're gonna learn how to create schemas on the client side now which are very similar to schemas on the server side and why you need them in the first place. So why? In addition to managing data from your API Apollo client can also manage local state originated from your front end app.
[00:00:42] Stuff you would normally store in something like Redux or view. You can create a schema to define that state, which allows you to query for that state the same way you query for your API data. So, that's basically a long way of saying you can define the state that you create locally in your app the same way you define state on your server, which is a schema.
[00:01:05] And then you can use graphical queries to retrieve that state. And you can mix those queries in with the exact same queries are used to retrieve state from the server. You don't have to make separate queries, you can make one query that gets. Server data and local data at the same time and Apollo will resolve them for you with no changes to your code, no issues.
[00:01:26] Your app will never know what came from local and what came from server, it won't even know, it's the same thing, it's pretty legit. So, yeah like I said, the same way just like the server, all you have to do is extend the types that your server schema has created for you.
[00:01:43] And then you have to use what is called a directive and I'll show you what directive is to access the local state from your queries and mutations. So what do I mean by that? Let' get into the example. So if we head over to client JS, and let's say we wanted to add a new type to the user.
[00:02:02] Let's just make a new type for the user. The first thing you have to do is you have to make a schema. So to make a graph scale schema, you need two things, you need some type definitions and you need some resolvers. Resolvers are functions that are responsible for getting the values for the fields on your type definitions.
[00:02:22] So let's just make some type definitions here. So, we'll say type defs and we're going to use the gql tag here, just like we do in our crazy mutations and we're gonna use what's called the schema definition language. The schema definition language is slightly different than the query language that you use to make queries and mutations, so what we need to do is use a keyword here called extend.
[00:02:44] And because we're trying to add a new field to the User type, we're gonna extend the User type here. So extend user, like that, or extend type User. And we know we have a User type, because if you go back to our code which is somewhere around here, we go back to this.
>> Scott Moss: We can look at our schema.
>> Scott Moss: And we can look for user, there we go, user type has an idea username and pets. So we can extend this to have whatever else we want. So we're gonna extend it to add a field for, I don't know, age.
[00:03:30] We'll add a new field that says age, if you needed to know the user's age for some reason. So we'll extend it, we'll give the user an age and we'll say its type is integer like that, okay? Everybody follow me so far? Okay, then we'll make some resolvers.
>> Scott Moss: We'll make some resolvers which is gonna be an object that maps directly to the user type which is also an object. And we're gonna make a function that's going to be executed when we are interested in the age of a user. So, if we want an age of a user, I'm just going to return a hard code of value and say
>> Scott Moss: 35, all users are 35.
>> Scott Moss: It's an integer that matches up with this.
>> Scott Moss: Everybody follow me here? Okay, and all we have to do from there is add it to our client down below. So we can say here's some resolvers and here's some type definitions.
>> Scott Moss: Right, so we're defining some local state, age does not exist on the server.
[00:04:44] This is not gonna push it back up to our server, and then our server has to do something. Nope, this is all local. We can do whatever we want with this,wWe can derive this from anywhere, we can do whatever we want. This is local state. And we're just adding it to Apollo, so Apollo knows about it.
[00:05:00] And we're extending it on the user type. So now, if I go back to pets, I know pets have an owner. And I know that because if I go look at the pet type, there is an owner here, which is a user type. And a user has a ID and username of pets, so what I'll do is I'll grab the owner and I'll grab the ID of the owner, always grab the ID and then what I want, is I wanna get the age.
[00:05:27] But if I just put age like this, this is gonna go to our server, and our server's gonna go, like, what's that? I've never heard of that, I don't know what age is. So we have to tell Apollo like, okay actually this one doesn't need to go to the server.
[00:05:39] So this is where the director was talking about his, he's the director of these outside, like this and you'll just say client.
>> Scott Moss: This is saying, this age phil is only on the client don’t go to the server with it, keep it here and give it to the client.That's basically is, and that's the direct to syntax, you can have directives to fields types, you pretty much add the redress to anything.
[00:06:08] On the schema side and the query mutation side there’s different types of directives. But this is the client directive that we get for free without Apollo. All right, so once we have that, we can kinda take a look at this data. So, let's just say console.log data.pets. And we'll just maybe look at it like the first one, see what happens.
[00:06:34] Cool, so we got that
>> Scott Moss: Get rid of that thing and refresh this, go look at this log here. We get back in Object, we go look at the owner and then wow, there it is. The owner has an age of 35.
>> Scott Moss: So we were able to merge some local state that we had, we extended it from some server type that we created on the server, either we did, or someone else on our team, or whatever API we're using.
[00:07:03] And we were able to mix them together seamlessly, and we didn't have to make any code changes, as far as our components. They don't really need to know anything, they don't even know if this came from, you couldn't look at this and say that it came from local state.
[00:07:14] How would you know? It's Summer's object.
>> Scott Moss: That right there is super powerful. So Apollo's just came out with this, I would say probably not too long ago within the last year or so. And that's like one of the best features that's kind of like why they rip.
[00:07:29] They used to have Redux built into the Apollo client. They rip it out and the opposite for their own thing, and I'm glad they did because they enable them to build stuff like that. And this is where you can kind of start replacing Redux with your own stuff, because you can just store local state and the way you resolve it is by creating a schema with some type daps that you either created or extended yourself.
[00:07:49] And you just resolve them however you want, they're just resolvers, you can make a resolve or do whatever you want to take the same arguments. As the resolvers on the server side which would be the current user in this case, so the first argument. They would take any inputs that you had or any orders that you had, they will take some context here that would be created for you from Apollo.
[00:08:12] And even an info with an AST of the query that you're trying to create, just like a server would. And you can do whatever you want to resolve that value. So the client side state management is pretty powerful.
>> Speaker 2: And all of these changes have to trickle down through our response to adding a pet to our optimistic response from having added the pet.
>> Scott Moss: 100%, so really even user here, we even have an optimistic response for user, but yeah if this was a pet, and we added a field to the pet. Then you bet you gotta go back to the optimistic response and add that field on there.
>> Speaker 2: But since our get AllPets has the owner on it, that same data structure has to be on there.
>> Scott Moss: Yeah, yep, so since I added the owner here on my AllPets, not only do I have to add it to my mutation.
>> Scott Moss: I also have to add it to my optimistic response. So that's kind of annoying, right? So that's good, because that leads us right into the next thing that I'm about to talk about.
[00:09:11] [LAUGH] So that's really great. So this is what I was saying, GraphQL can pretty much be executed anywhere. This, we're not even in a server, we're on the client and we're creating schemas and writing resolvers, because that's all GraphQL does. It's a very simple function in fact underlying tool for every GraphQL process that I've ever used is a little function from GraphQL JS that takes in a query or a mutation, a schema, some resolvers, some context in the root value, and it returns you a resolved value.
[00:09:41] That's all it does, that's literally all this stuff does. It's very simple, you can pretty much do whatever you want with it, and there's new, crazy ways people are starting to do, new things that people are starting to do with GraphQL that it's changing a lot of stuff every day, so this is one of them.