This course has been updated! We now recommend you take the API Design in Node.js, v3 course.
Transcript from the "Mutations Walkthrough" Lesson
>> Scott Moss: So let’s talk about some mutations here. I’m gonna check out to the branch so I can actually do some mutations, git checkout.
>> Scott Moss: Okay.
>> Scott Moss: All right, so I should have some mutations here.
>> Scott Moss: Cool, so the first thing you'll notice when you actually have mutations. This is from a client's perspective, this docks, you can think of it as our client.
[00:00:37] We're active, we're looking at our server from a client's perspective. You'll see mutation here, next to query, I think you'll see all these mutations. Very similar to what you would see with queries. And remember, my convention is, I use input, so you'll see that a lot. So let's go ahead and let's do some creations or some mutations.
[00:00:56] The first thing you need to do is, you actually have to type in the word mutation here. Now, I haven't told you about named queries, because we didn't really need to do them. But this is a named mutation, so you put the word mutation in it. So you might be thinking, is there a word for query?
[00:01:10] Yeah, there is, the reason we didn't use it is cuz we don't have to use it. The only time you have to use named queries is when you're doing some advanced analytics on the back end, or you're doing some caching on the front end. Inside this, right now, we're not, we're not doing any of that, but yes, you can do named queries.
[00:01:24] If you do something like Apollo, you most likely will do named queries. But for mutations, you have to, there is no shorthand, anonymous mutations that you can do, like you can with queries. You have to use mutation followed by the name, the name can be whatever you want.
[00:01:38] My convention is, I just like trying to name is something similar to the actual mutation that I'm about to do, and then title case it. Title casing is starting with uppercase and then camelcasing there. So let's do a new song, I think we did this before, let's do it again.
[00:01:54] So we'll say CreateSong, right, so that's the name of our operation, that's the name of this operation, it's called CreateSong. It's not the name of the mutation, the mutation is going to be newSong, down here, so it's already created. This is the operation for it, you can call it whatever you want.
[00:02:13] It's gonna be used, like I said, for advanced features on the back end, if you're tracking those names. Or caching on the front end, like I know Paolo uses it. So then what we would do is, we would look at the new song mutation in our docks. And we would see that it takes one argument called input whose type is NewSong, title, url, album, artist, rating, favorite, right?
[00:02:37] So what we'll do is, we'll make input with a $, you have to put the $ in front of it. That's a special character that's indicating that this is a variable that's gonna be passed in, so that's the first thing. And then you have to give it the exact same type as it's displayed in the mutation that you're about to call, in this case, that type is NewSong.
[00:02:58] It has an input type of NewSong with an exclamation, so we have to do that exact thing, NewSong with the exclamation. And then now we can actually issue the mutation, which is newSong, you can see it all completed. It has a type of input who's value is the variable called input.
>> Scott Moss: Now, because this is a variable, you don't have to call it an input. You can call it whatever you want, as long as it has a dollar sign in front of it. Doesn't matter, you can call it thing, doesn't matter. Cuz this is the one that matters, it has to be bound to this.
[00:03:49] And if you have to remap them in your mind, like, yeah, yeah, thing goes to input. It's easier to just be like, input's input, id's id, number's number. Versus try to map them together, at least with my experience. So we'll do the newSong, and then we'll just get back the ID and the title.
[00:04:06] And then we'll alias this as song, right, so then we come here, we make some variables. What's the name of the variable that we need?
>> Speaker 2: Input?
>> Scott Moss: Input, yeah, it's just called input, boom, so you got input, it has a title, we'll say title is Jams. We'll also give it an artist of, I don't know, Kelly.
[00:04:38] And then we'll just give it a URL of some fake URL.
>> Scott Moss: Cool, so we got that, we see our input object there. We're ready to go to make this mutation, and if we satisfy the requirements, we should be able to create one. So we hit this, you can see it created something, it came back and it gave us the properties that we wanted, the ID and the title.
[00:05:07] And all that worked because this mutation satisfied the request here. It satisfied the song type, so because this is the song type, we can feel assured that if I ask for any of this stuff, I'll get it back.
>> Scott Moss: Everybody following me so far, in this mutation, okay?
>> Scott Moss: So that's how you would make a mutation from a client's perspective. Now, how do we actually create this on the backend? It's like the exact same thing is occurring, it's not that special, in fact, it's literally the exact same thing. The only difference is gonna be what you do in the resolver.
[00:05:43] How you set it up in GraphQL is the same thing, so let's go look at the GraphQL for the user, which should already be there if you're on lesson 12 branch. You'll see on the user, it defines a type mutation. You can think of the user, if you probably have forgotten, it's like my index query.
[00:06:01] I'm defining the query types and the mutation types, and everywhere else, I'm extending it. So you usually do that on one file, you'll define the mutation type, the query type, and then you extend them everywhere else. So I'm defining the mutation type, I'm putting a field on it called updateMe, which resolves to a user type.
[00:06:21] So just by looking at this, what does this tell you our resolver's gonna have?
>> Scott Moss: What's the name of a function in our resolver to resolve this?
>> Group: updateMe.
>> Scott Moss: Yeah, it's the same name, right, remember, they have to match. So that means we have an updateMe function inside the resolver of the user.
[00:06:42] So if I go to user.resolver, there it is, there is an updateMe on the mutation type. That's important cuz this is the mutation type, here's the field on it whose value is a function that returns a user type, that make sense?
>> Scott Moss: So that's how you write a mutation, it's literally, the only difference between this and a query is that it's underneath a mutation.
[00:07:07] Other than that, it's the same thing, it's just whatever you do in your resolver that's different. Here I'm actually mutating something, this would not work because it's assuming the user is there from the adjacent web token, which we did not activate yet. But assuming that it was there, yeah, you would save this, and it would update.
>> Scott Moss: Any questions on mutations?
>> Scott Moss: So remember, first argument is a root value. Second argument is the arguments that'll be passed in from as you see them.
>> Scott Moss: As you see them, this one doesn't take an input, actually it should. It should take a input whose type is,
>> Scott Moss: updatedUser, exclamation, there you go, so now that one takes an input. So as you see them in GraphQL, you see this input here?
>> Scott Moss: It matches this input here, if this was called x, this would be called x.
>> Scott Moss: And again, this is just a shorthand for destructuring, this isn't actually an object with an input property on it.
[00:08:18] I'm just destructuring it in the arguments. If you don't like that ugly syntax, that's totally fine. You can just do args, or whatever you wanna call it, and now it's just args.input.
>> Scott Moss: If you get lost in the sauce here, just do some console.logs. That's the key to debugging, is console.log.
[00:08:46] It's key, it's key in React, not React, I'm sorry, it's key in GraphQL, it's also key in React. Any questions on mutations, yes?
>> Speaker 4: They get me, what is the second input?
>> Scott Moss: Get me this one?
>> Speaker 4: Yeah, before user, what is that?
>> Scott Moss: This is just another placeholder, I'm not using it, so I'm just putting something there so I can get to the thing that I really wanted, which is this.
[00:09:11] This is a placeholder, this is my convention of putting placeholders, because if I just did this, then it would try to get the first argument. If I just did this, then it would try to get the second argument. So this is just me saying, I just want the third argument, but I have to put something there.
[00:09:28] I mean, there's more elegant ways for this, yeah, there's definitely more elegant ways for this. You could do that, and you can be like, return args, whatever you wanna do. There's better ways, well, that's just how I'm doing it, I like to be explicit about stuff.
>> Speaker 5: Just as you have to your query in arms, right?
>> Scott Moss: Right, yeah, any other questions?
>> Speaker 6: Query and mutation, are they each a type of resolver?
>> Scott Moss: So resolver is not a type, all the resolver is is just, so think about it like this. By default, GraphQL will attempt to do its own resolution, it will attempt to do its own resolving.
[00:10:10] And when I say attempt, basically what it'll do is, it'll look at the object that you gave it. If the property names match up with the object you gave it, it'll resolve it. If it does not match up, it'll expect there to be some functions on that object somewhere.
[00:10:23] And those functions better resolve the type that it's looking for. So there is no type resolver, you could think of mutation as literally the same thing as query. Except you just put stuff in the database, other than that, it's the same thing. They all have the exact same syntax for resolvers, they all take the same area like root value, arguments, contexts, info.
>> Scott Moss: The exact same thing, so mutations resolver, the only difference it would be would be the logic that you wrote in it, but it does the same thing. Whatever it returns needs to satisfy what the return value of that mutation is. Does that answer your question, or was it something else?
>> Speaker 6: No, it's good.
>> Scott Moss: Okay.