This course has been updated! We now recommend you take the Advanced GraphQL, v2 course.
Transcript from the "Arguments" Lesson
[00:00:00]
>> Scott Moss: So enough of that talking. Let's [LAUGH], let's do some stuff. So let's make a new project here. Make a new project. We'll just give it an input. New project input, I believe. And this is the thing about having conventions, I didn't really have to look, but I'm guessing my thing is called new project.
[00:00:23] Yes, I made it, so I should know that. But also because I always give it the same thing, NewProjectInput. So the way I like to name my inputs is basically the name of the mutation or query followed by the word input. And that way I never forget what the input names are.
[00:00:36] And trust me, you will forget. And you will look at it, and you won't know what's going on. That happens to me all the time. So we're gonna do a mutation here for our new project. So let's create a new project here. And we can see it takes input.
[00:00:51] There is gonna input, and we'll just get the name, actually we'll just get the ID here. And we'll play with this so that you can see what I'm talking about. So let's get the ID, I'm gonna pass in an input here
>> Scott Moss: What does it take? NewProjectInput, there you go.
[00:01:12]
>> Scott Moss: So it usually autocompletes, I guess it just doesn't feel like it. I'm in headers, there we go. There we go, okay, so it takes in a name, we'll just call this Frontend Masters, there we go. So we'll create this, and we get this id here. So we got this project with a nice id here.
[00:01:33] Now, let's play with this resolver to see exactly what I'm talking about. I'm just going to add a log here just so you can see what I'm talking about. So I'm going to say hello in id resolver. So now I'm going to add that log, I'm gonna go back here, I'll refresh just in case.
[00:01:51] I need to make a new project name because it's unique. I'm just going to run this again. And if I could look at that log, you can see hello in id resolver. So when I ask for the id, it actually executed the id resolver. Remember, so if I don't ask for this id though, and I just type name here, change the name, and let me clear this, and I run it,
[00:02:20]
>> Scott Moss: It's not gonna log. It didn't actually execute the resolver because I didn't ask for it. All the resolvers get random because that what the query demanded. So this is what I was saying, you don't have control over when your resolvers are gonna be executed. They're gonna be executed when someone asks for them.
[00:02:36] So if you think about it that way, how do you create it in such a way that they are gonna run it exactly the same, no matter what is given to them. And they only resolve the value of which they are responsible for, they don't resolve something else.
[00:02:50] Until you get to really advanced stuff, then maybe you can do that but you won't normally do that. So in this case, id just returns whatever I wanted it to, and notice I don't have a resolver for name here. There's no project's name resolver here. So how was I able to get the name, anybody know?
[00:03:10]
>> Speaker 2: Just declare on the type.
>> Scott Moss: Yeah. Yeah, exactly. This project actually has a name property on it. So let's actually go through the order of execution. So I'm gonna do this. So you can get a really big picture of what's happening. So we have projects resolver. And then we've got id resolver, right?
[00:03:38] So let's do that. Come back here, refresh this. Make another one, and I'm gonna ask for ID as well. So we'll execute that, and let's go look at the logs. So you can see, I'm sorry, I put it in the wrong one. I put that in the resolver, it should be in the mutation.
[00:03:59]
>> Scott Moss: Let's put, here we go, all right, so let's start that over and let's make another one. All right, so we'll run this, clear the console, there we go. And now you can see the first thing that ran was project resolver. And then because I asked for id, the id resolver then executed second.
[00:04:23]
>> Scott Moss: Now, the reason that happened in that order is because that's what the query was asking for. So let's look what's actually happened. So first thing that we ran was new project, right? So that was the actual mutation. So there is a resolver for that mutations right here.
[00:04:36] So that's why this logged. And then, after that resolved, we ask for the id. So when you ask for the id, it actually ran the id field resolver for the project type, which was this function, right? Now, I talked a lot about this in the last course. The next thing to talk about is what to actually do here with this stuff.
[00:04:57] So notice I got this argument here called project. On these top level resolvers, all of these are null. I just used the underscore as placeholders, there's nothing there. But this one actually has a first argument, and that's because something got resolved before it. In this case, what was resolved before this ID resolver was this new project.
[00:05:21] So whatever this new project return, gets passed as a first argument to the nested resolvers. And that's how I'm able to resolve the fields for the type project, because I'm given the actual project as the first argument. That's how you know you are inside of a nested resolver is when you're actually passing things out.
[00:05:41] But this newProject was not aware of that. This newProject didn't know that there was gonna be an ID resolver underneath it. All it did was, I just need to return an object that looks like this, something like this, and if I don't return something like this, I hope there's some resolvers underneath me that's gonna resolve them.
[00:06:02] That's basically it. So if I decided just to return an empty object here, it will still work as long as I resolve all those fields that are being asked for here. Does that makes sense? But if I don't resolve those fields eventually GraphQL, I tried to resolve it, I look everywhere, there's no resolution, I'm just gonna break.
[00:06:21] So all that has to be resolved. Any questions on that order of execution? Yes?
>> Speaker 3: So even though your type create project, or new project, says it's going to return a non-nullable, if you return an empty project from that resolver, GraphQL's gonna be cool with that?
>> Scott Moss: No, so let me explain.
[00:06:45] This new project here, let's say I return an empty object, and I will. I'm just gonna return an empty object, right? I'm just gonna save that. And then inside of ID, I'm actually just gonna return,
>> Scott Moss: Just that. Okay? So let me refresh that. Make sure I'm only asking for id.
[00:07:05] Do you think this is going to break? Because now that I'm returning the id object?
>> Speaker 3: No, because you had the resolver for that.
>> Scott Moss: Right, I have a resolver for the id. But as soon as I ask for something that I didn't make a resolver for, like name, it's gonna break because I never resolved it.
[00:07:25]
>> Speaker 3: So in your project GraphQL, you have on line 26 it says that newProject will return a non-nullable project.
>> Scott Moss: Exactly, so newProject is, all right, let me explain it like this. NewProject is going to return a type called Project, right? But then Project is also a type that has its own resolvers on it.
[00:07:50] So although newProject did return something, GraphQL is not doing the validation check right here. It's not going to check to see if this was the same shape. It's only going to check to see if the result of the query. Once it's done, it's the shape that it's supposed to be.
[00:08:04] So it's about where the validation happens. So I think you're expecting this return value to be exactly this. But in fact, this return value could be anything. Because at the end of the day, as long as the operation resolves to the type of this, then it's fine. And we know, because we declared different resolvers for this type, that this is not the end of the operation.
[00:08:27] It's actually gonna go down to this next level, which is here.
>> Scott Moss: Does that make sense? So I didn't put a name here and I didn't put a name here. So when it tried to resolve name because I asked for it, it failed. But when I only did id, which does have a resolver for it, it passed.
[00:08:41] And the id is on the type of project. So it was totally fine. It's not trying to validate this shape, it's trying to validate the query. Right, this query has an id and a name, it better match that. It doesn't have to match the whole object or the project.
[00:08:55] It's only what the query asks for. Right, so if I ask for every single field on here, yeah, it better have those.
>> Speaker 4: [INAUDIBLE] because they're required, right? If you make name not required it won't blow up.
>> Scott Moss: Exactly. If I didn't make name required, it still wouldn't care.
[00:09:09] It'll just be no. It's only because it's required, yeah. It can get pretty tricky. All right. Any more questions on that?
>> Speaker 5: Yeah.
>> Scott Moss: Yes.
>> Speaker 5: So you talked about the first argument is root. So it's null, and then because you return a project, it becomes a root in the actual resolver for the project?
[00:09:30]
>> Scott Moss: That's exactly right.
>> Speaker 5: Will it just keep passing root, whatever the last root was, just keeps getting passed down?
>> Scott Moss: Yes, whatever you return from the previous resolver, if there's another resolver underneath it, the value of the previous resolver is the root. Yeah, it won't combine them or anything, you can't go get your grandparent but you only get what was before you.
[00:09:49]
>> Speaker 5: Right.
>> Scott Moss: And that was it. If you wanna share things across, that's what we're getting into next. But any other questions on this? Yes?
>> Speaker 6: Quick question. If you return underfined or null from resolver, would that break the chain?
>> Scott Moss: If you return undefine or null, no.
[00:10:08] Again, the chain is set up by the query. When you write these resolvers, you have no control of what's gonna happen next. So the only thing that's gonna break the chain is if somebody decided not to write a query to do that. So if I were to return undefined, which I can't here, I'll do it as an example.
[00:10:29] If I were to return undefined in this mutation, or null, let's just put null. It's still gonna go down here and try and resolve this. But what's gonna happen is because this is not an object, and this is trying to place a property on an object, you're gonna get a error probably in JavaScript but not in GraphQL.
[00:10:56] Does that make sense?
>> Scott Moss: So it's not so much a validation thing, it's more of a type thing. JavaScript is probably not gonna allow that, unless GraphQL is smart enough to resolve it. So let's check it out.
>> Speaker 7: [INAUDIBLE]
>> Scott Moss: [LAUGH] This is where Scala comes in. Scala.
[00:11:15] So let's see. So we'll say that. Yeah, so actually it looks like GraphQL actually did intercept this. All right, cuz GraphQL, actually what they do is they wrap your entire query inside of a try catch, so they actually catch every single error that you have, and they try to take care of it for you.
[00:11:31] So in this case, because there was no object to put something on, yeah, it just freaked out. So at minimum, yeah, you would probably need an object here.