Server-Side GraphQL in Next.js

Editing & Deleting Issues

Scott Moss

Scott Moss

Superfilter AI
Server-Side GraphQL in Next.js

Check out a free preview of the full Server-Side GraphQL in Next.js course

The "Editing & Deleting Issues" Lesson is part of the full, Server-Side GraphQL in Next.js course featured in this preview video. Here's what you'd learn in this lesson:

Scott discusses the input arguments required for editing an issue, such as the issue ID and optional fields like name, content, and status. He also demonstrates how to create the resolver for the edit issue mutation, which includes authentication checks and updating the issue in the database. The delete functionality is left as an extra credit task for both the server-side and client-side courses.


Transcript from the "Editing & Deleting Issues" Lesson

>> Scott Moss: Okay, let's hop into the other mutations that we have. So let's look at my notes, we have,
>> Scott Moss: A few more, we have Edit Issue and Delete Issue, so let's do Edit Issue. Edit issue is quite simple, we're gonna use this to edit the status of an issue.

So we can create an EditIssueInput that have all these optional things because I don't know which one of these you wanna edit. You maybe wanna edit the name, maybe the content, maybe the status, or a combination of these three. So those are all optional, but you definitely have to give me an ID so I can identify what issue you want me to edit in the first place.

So give me an ID here. So that's what we need to do. And then we need to create a mutation for edit issue and make it return an issue, so let's do that. Let's go to our schema.
>> Scott Moss: We'll make an input here for Edit,
>> Scott Moss: IssueInputs, it's gotta have a name, that's an optional string, a content, that's optional string.

A status, that's an optional issue status, and then an ID that is required.
>> Scott Moss: And then we just need to make a mutation. So we're gonna say editIssue, which is gonna take an input of EditIssueInput required and it's gonna return a non-null issue. The reason I'm making this a non-null issue versus the create issue, which wasn't, it's, there really is no right or wrong answer.

This is mutating something that's existing, so I'm expecting it to return an issue, otherwise it should break. Whereas this is trying to create something that doesn't exist, so there's a potential that it might break. So it might just return null if it couldn't create one. Whereas, if I tried to edit the status of an issue and for some reason it couldn't find it, then yeah, I would want this to break, so that's why I would do it.

There is no right or wrong answer, I guess it's just a user experience. But for me, I'm like, if you're trying to edit something and you gave me an ID and that's not real, then I want this to break.
>> Scott Moss: Whereas this, you could also have the same argument, you could say, well, if I tried to create an issue, I should always want it to create an issue or it should break, it's totally up to you, whatever the UI is.

>> Scott Moss: Okay, let's make our resolvers, so, if we go back and look at our notes, we only have to make one resolver here. We have to make the resolver for the edit issue, which is very simple, we do our off check, we flatten out our fields, and then we issue the database query, so, let's do that, go to our resolvers.

We're gonna go to the mutation object here. We're gonna say editIssue has to be the same name that we put in the schema, like that. There is no parent cuz it's on the mutation, it's the root, so there is no parent. We do have an input argument here.

Always call my arguments inputs so for me it's always input you can call whatever you want in your schema. We do need the context from the user and like always it's the resolvers responsibility to an enforced authentication, so we need to check here.
>> Scott Moss: Later on I can show you how you can create a higher order function to do this for you if you wanna know what I'm talking about I can do that.

If we look at,
>> Scott Moss: If you look at the input, the input is gonna be all the flat properties on there plus the ID. We need to pop the ID off cuz that's not gonna go into the updates object. So I'm gonna say const, give me the ID and then everything else is just like the update of input.

>> Scott Moss: Kinda also just went into the schema and made two different inputs, right? You could also say, okay, the input is gonna be like everything you wanna update. But there's also a second argument called ID that's ID, you could have did that too. That's probably more common, you might see that.

And that way, I just take the ID off of this, and now the ID is the second argument. So there's really no wrong answer.
>> Scott Moss: But because I did it this way, I'm popping the ID off so I can just feed this object directly into my database without putting this there.

>> Scott Moss: There we go. So got that, and I know the inputs there because, it's got an exclamation on it, so it has to be there.
>> Scott Moss: All right, so we got that. And then now we wanna say results = await db.update on the issues table .set. We wanna set the update here, but the thing is, you might not have passed anything here.

So literally, what you probably wanna do is do a check on update here to see if there's some fields but that's just so much work, I'm not doing it. So I'll just say, you know what, something like that, we could do that. And then we wanna say where(eq(issue.userId is equal to ctx.user.Id/.

So only update the issue or I guess, yeah, we wanna do that. We wanna do an and here actually. So we wanna say where and that, so the issues user ID belongs to this user and the issue.Id is the same as id, so both of those have to be true.

And then we need to do returning, otherwise it will just tell me x amount of rows updated. I wanna actually get the updated things back, this is always gonna return an array. I just wanna get the first thing, so I'll just say,
>> Scott Moss: Which is the updated issue.

>> Scott Moss: If you're looking like what the hell is this double question mark, it's basically the same thing as,
>> Scott Moss: This, except for this, will fail on falsy values that are actual values. This would fail if the left was zero. But maybe zero is a valid value for the operation you're doing.

So it'll fail on falsy values, whereas this would only fail on null and undefined. So if this was null or undefined, then it'll do this. Whereas but if the left was zero, that would be considered truthy and it would just read that. So I think in most cases you probably want this.

We got the editIssue, let's go try to editIssue. Let's go see, see what the vibe is here. Let's go up here, let me grab this issue. Let's get this issue d right here, let's grab this one. So I got my issue id, I'm gonna go back, I'm gonna uncheck that one.

I'll go back here, I'm gonna uncheck that. Let me clear these inputs down here, make a mutation, do a editIssue. I'm gonna edit the status, so then we can try to do this status filter on our issues query that, we haven't tested out, I forgot to do that.

So I'll get the name, the id, and I want to edit the, I'll pass the id of course. I want to edit the status, so let's do that. Here's the iid and then for the status, they're all backlogged, so I'll change one to INPROGRESS. So let's do that.

What did we get here? Cannot return null for null-field Mutation.editIssue, we got an error. Let's see, might be a Davis error. I guess the only thing I can think of is like this id that I copied is not an issue id. So let's get another issue id from here make, make a new tab and issue another request, and do a query for all the issues for this user.

I'll just grab all the ids and then the status, and then I'll grab,
>> Scott Moss: And id, make sure I get it correct. There we go, I'll go back to this. I will go back here, at this one and let's run that. There we go, yeah, I guess the id that I pasted it was just not right.

So that works, I changed it to INPROGRESS. So now that one's INPROGRESS, what I wanted to test was this query where we can do the issues query and then add the arguments here for statuses. And for statuses, I'm gonna pass an array of only INPROGRESS. For this user, it should just be one, and it is, it's just one.

If I say give me all the ones that are backlog, it should be, I don't know, more than one. Or I guess I only have two. Let's see, backlog and INPROGRESS, let's see. Yeah, I guess his user only has two, so there we go, so that filtering works.

Yeah, I guess I just copied a wrong id or it didn't belong to that user or whatever, but yeah, code looks right, so that works. Let's check it out on the app.
>> Scott Moss: We go to here, the app. The way you want to edit is if you click on one of these status rings, you can change it, so I'm gonna say INPROGRESS.

It changed to yellow if I refresh, you can tell that it's yellow. It jumped down because that's the sequel sorting, whereas the front end doesn't do the same sorting. I talk about it on the client side, of course. I can change this to done, and that works as well.

So it looks like our update, our edit works just fine, our create works fine, our git works fine. So for the most part, that is the functionality to app. We still have the delete functionality that we can add, but there is no UI for that. On the client side, of course, I left it as a extra credit if you wanted to add a UI to be able to delete an issue.

On the main branch, I have the delete mutation implemented, so you can just write the front end. Now for the back end, the extra credit would be for you to make the delete implementation or the delete mutation. So therefore you can delete it. So that's something that I will leave up to you all, to get going

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now