Server-Side GraphQL in Node.js Mutation Solution
Transcript from the "Mutation Solution" Lesson
>> Scott Moss: All right, welcome back. Hopefully everyone had enough time to create some, or create a mutation for the pets. And if you had some more time to explore, you might have even created some update mutations, or delete mutations. But let's just focus on the creative mutation for pets.
[00:00:18] Anybody have any questions before I get started, or the solution?
>> Scott Moss: All right, so let's do that. So what we'll do is make a new type here in the schema called mutation, like that. And we'll make one for a new pet, you can call it whatever you want, no right or wrong here.
[00:00:38] And it's gotta return a pet, that's always required. And I'm going to make a new pet input, NewPetInput, and that's always gotta be a name with a string. And it's always gotta be a type of string. And let's say this is input, and it absolutely has to take a new pet as input, no if, ands, or buts about it.
[00:01:04] So that's updating our schema to have a mutation called new pet, that takes an argument with a name called input. Whose type is a new pet input, that's required, and it returns a pet type that is also non-null or required. Everybody following me so far, yes? Why do you need to require that the pet is return?
[00:01:26] Cuz what if the new pet creation fails? If the new pet creation fails, that's a good question. So this non-null thing does not account for any errors that might happen to your resolver. This is saying if your resolver did return, so assuming no errors happened, it better return a pet.
[00:01:46] If an error did happen, then that error is gonna be thrown and knock this non-null error. But yeah, good question.
>> Scott Moss: All right, so then we will go to our resolvers here. Uncomment this mutation thing, and give it the same name, newPet, just like we did our queries.
[00:02:07] We have nothing here, we have an input here, and we got some context here. So I'm just gonna return, or I shall say be very explicit about this. Pet = ctx.models.pet.create, I believe is the method. And it should be able to just pass an input there, and I was gonna return the pet.
[00:02:35] Pretty simple, let's start this. All right, nothing broke, that's always good when nothing breaks, so it's a good feeling
>> Scott Moss: And cool, we got a new pet mutation here. Input looks good, new pet input, that's non-null. Pet type looks good, new input, non-null name, non-null type. Everything is looking good, so let's do that.
[00:02:59] So make a new mutation here, and we'll say new pet.
>> Scott Moss: And we'll go ahead and pass our input, which is an object type. And it takes a name, Daryl. I really miss Daryl, if you hadn't noticed, and a type cat. So look at the ID, make sure the ID got created, look at the type, let me get the created at, see what happens.
[00:03:30] Boom, there we go, got a new path here. So if we were to go look at the db.json, we can see that, here it is, here's the path that got created. So you created Daryl, and it returned to previous Daryl. No, your mutator, your query returns three for every ID.
[00:03:58] Yeah. The ID is just three. Yeah. Not in a string. Yeah, I should get rid of [INAUDIBLE] that's confusing, there we go. [LAUGH] Let me get rid of that, I'm sorry, that was really confusing. Let's run that again there. There we go, there's another one. Any questions on the mutation stuff?
[00:04:20] So how come that doesn't update then, instead of why isn't it updating? Cuz we already have a Daryl that's a cat. Are you saying why is it not updating the Daryl that we already had? Because we didn't write the resolver to do that. So if you wanted to do that, so I mean, let's look at the mutation here, this mutation.
[00:04:38] All it does is create it, we didn't tell it to update. If you wanted to do an update, then I would make another resolver, and another mutation called update that, like this. And this will take in something like that. It'll take in an input, which is whatever fields you want to update, taking the context, stuff like that.
[00:05:00] And then I would say pet = ctx dot, or context.models.pet. And if I had an update method on here, which I don't, I would just say update. And I would say first find it by the input.id. And then I wanna use an input.updates, which are the updates that I want to get back on the pet and return that like that.
[00:05:29] And then you'd just have to go make this mutation inside your schema. So it's because we just didn't do anything. I mean, we didn't account for that, we can do whatever we want in our resolvers. And we didn't choose to account for that, we just went ahead and created a new one.
[00:05:42] And this is not a real database, so names and stuff aren't indexed, so you can just make whatever you want. Any other questions? So GraphQL doesn't care about what these mutations do, and how they do it. Exactly. Do any of the frameworks have constructs for that stuff, or is it you use bit freewheel to do what you want?
[00:06:08] You can do whatever the hell you want. There's literally nothing, that's the whole point of it. The closest you're gonna get to that is you're gonna get helpers from libraries, or from frameworks that help you do whatever you want. There's things like data loaders that help with runtime response queries.
[00:06:26] There's things like data sources that Apollo actually provides to help you use, to interact with third-party rest APIs. There's bindings to databases like Prisma. Prisma does that. Prisma binds to a database, and gives you like a GraphQL ORM. So you can basically query your database using a query, using a GraphQL query.
[00:06:50] That sounded really complicated, but that's what that does. But yeah, you could do whatever you want, there's no restrictions around it. The only restriction is that your resolver returns the specified type for the field that it's responsible for, how you do it doesn't matter. All in the same lines, admittedly, my brain conflates GraphQL with graph database.
[00:07:16] Yeah, they kinda work hand in hand, yeah. Is there any tradeoffs with using relational database in the graph database? Are there tradeoffs with trying to use GraphQL with relational databases? I mean, do you find yourself butting up against performance issues with that? So we're about to get into relations, I wanna talk about that a little more.
[00:07:37] But yes, there are performance issues, but just like you using a rest architecture, there is different solutions there. You have to get a lot more creative with those solutions, because it's not as simple as just throwing Redis in front of your database and calling it a day. It's literally not that simple with GraphQL, because anyone can enter your graph at any node.
[00:07:58] And it's like, what do you do? You cast a whole response of that query? Cool, I added a new field. It's a different query now. Okay, I must have cached it. So there's a lot of different things you have to account for, but I'll talk about those, the specific performance stuff in the events course.
[00:08:16] But yes, you will have performance issues, 100%, guaranteed.