API Design in Node.js, v4

Create & Update Product Handlers

Scott Moss

Scott Moss

Superfilter AI
API Design in Node.js, v4

Check out a free preview of the full API Design in Node.js, v4 course

The "Create & Update Product Handlers" Lesson is part of the full, API Design in Node.js, v4 course featured in this preview video. Here's what you'd learn in this lesson:

Scott codes the create and update product handlers. Both handlers will not only send a product name to Prisma but also the current user's ID to ensure the product that's created/updated belongs to the user.


Transcript from the "Create & Update Product Handlers" Lesson

>> So we got get one product. Let's keep moving, and then eventually you will stop and add these to the routes and try them out. But let's just add some more, in that way, you have some more examples. So let's do, we got get one product, we got get many products, let's do create a product, so createProduct.

Same thing, request, response. And this one's pretty simple. So we can say product = await prisma.products.create. Instead of having a where field, cuz we're not searching for anything, we have to tell Prisma what data we're giving it to create something. So let's call it data instead of where.

And the data that we want to create, if we go back and look at our routes for creating a product, it's only gonna be a body, that's it. I'm sorry, a name on a body, that's it, there's nothing else here. But a product also needs a belongsTo. We just don't get that from the user.

That's gonna be on req.user. So we say data, name is req.body.name. And that's the brilliance of those inputs, is that now, we know 100% sure that req.body.name is there, because if it wasn't, this handler would never run. Because our input validation middleware would have saw that and sent back an error message before we got here.

So having that middleware allows your handlers to just flow very easily, and you can just safely assume that all the things are there, which is great. So you can see I'm still getting this cuz it's like, hey, you have a name or whatever, but now you might need something else, so we got name.

Now, we need belongsTo. So there is a couple of ways you can do this. So you can say belongsTo, and then you can just put the ID yourself. So you can say req.user.id and that works. When it comes to relationships, the other way you can do it is, ir I'm sorry, that would have be belongsToId.

There we go. The other way you can do it is if you wanted to do belongsTo instead of belongsToId, and you had the actual use,r which we don't, but if we did, you could say belongsTo. And then I believe you can do something like associate or match, there's a key word here.

Maybe it's not worth it. Yeah, just do belongsToId. That's the preferred way, but there's another way to do it, just almost never had to. So there we go, we got that. We got the ID, we got the name. We should get a product back, we're just gonna be naïve here, and res,json.data with the product, okay?

Keep it moving, we got the create, we got the gets. Let's do the update and delete, and then we'll try them out and see what's up. So create product, let's just say updateProduct, like so, async (req, res). So to update, there's so many ways you can do it in Prisma, but we can try this way.

So I'll say, await prisma.product., and if you just hit dot on that, you can see all the different methods they have. For instance, fine first or throw, this is really good, or find unique or throw. I really like this, because most of the time, If you do a query to look for something and it doesn't exist, the database won't throw an error.

It'll just send you back empty result, empty array, undefined. But maybe sometimes you want it to break, I'm looking for a user who's signing in. If that user doesn't exist, I want to throw an error. Otherwise you'd have to do an if statement on the next line yourself, anyway, so this kinda saves you that, which I think is really cool.

But anyway, here we go. So we have update, we have updateMany, we have upsert. I'm not sure if you heard of upsert before. Upsert just means like, I'm gonna give you some information, first try to find something that matches this. If it doesn't, then use this to create a new one.

So it's just like create or update. We're gonna use update, okay? So this one is just for updating one product. And you can see even Prisma wrote the documentation for it, it literally says right there, Update one Product. Pretty brilliant, we didn't write that. Okay, so update. There you go.

And then because update is also a find and a write at the same time, we have to use the where and the data. So first, we have to say where, so it knows what to find, right? And then outside the where, we have to tell it, when you find it, this is the data you need to update it with.

So we gotta use both. So for where, we'll say, where ID is gonna be rec.params.id. And then the data, if we go look at our validator for the product update, It's just a name, you can only update the name. So we'll just say name is req.body.name And then we get that.

And then usually on update, it's kind of you as an API person to send back the thing that you updated with the updates on it. Otherwise the client is probably just gonna make another request back to the server to get the updated thing. So just be nice and send back the updated thing, save them some time.

So that's what we're gonna do. And I'm pretty sure that returns the product, yeah. Now, if you do update mini, you will not get back an array of all the things you updated. You'll get back an object describing all the operations you did, and you have to make a query to get them all.

But if you update one, you'll get back the thing you updated, okay? And then last one is gonna be delete, the simplest one. So deleteProduct, That will be (req, res), Async, And then const deleted, Equals await prisma.product.delete. Delete kind of works the same way as update, where you'll get back the thing you delete it.

But if you do delete mini, you'll just get back information of how many things you deleted. So we're gonna delete where, id is req.params.id. I just remembered something, we just fell into a security flaw on the last one, [LAUGH] because we're just trusting that this is the ID that you wanted.

Okay, well, I found your product ID, now I'm about to delete it, right? How do I stop that, right? So you also have to do the combination of belongsToId of req.user.id. BelongsToId is not assignable to type. Where, BelongToId, yep, it's definitely there. I don't know why TypeScript doesn't like me doing that, but I'm gonna leave it anyway, cuz I'm pretty sure it's there, so req.user.id.

Because, yeah, without this, what's gonna happen is, hey, I'll just delete whatever ID you put here and it'll be gone. So you definitely don't want that. There we go. I don't know why that thing doesn't like me having this here. Maybe it wants me to manually find it myself and then delete it.

But I'm not doing that product where, yeah, it's going back to the index point. Delete is basically a find unique, and we don't have an index for this combination, so it's like, you can't do that. So this is why you would have to index this. So we'd either have to go back and index this, run another migration, regenerate the client, and/or have to find it ourself first and then delete it.

But just leave it like this. Yeah, your app's gonna be a wild, wild west, so people just screwing with each other. So we can go back and add the index. So I'm just gonna leave this here for now and then we'll add the index for it. Okay, so then we have to delete it.

I'm just gonna say res.json (data: deleted). And the same thing is true for the updated, we would have to add the belongsTo here as well, otherwise you could update anybody. And we're gonna get the same issue, because this is not unique. We gotta update that index. Okay, so I'm just gonna go do that right quick.

For the index, I think instead of doing that, I can say unique like that. So now, that's unique, an Id and a belongsToId But we have to tell the database about it. So in order to do that, I gotta go back into the terminal, And I have to, Run a migration.

So I'd say mpx prisma migrate, dev, I'm not even gonna give it a name, and so I'll just run it. It'll just come up with a name by itself, So this happens a lot faster locally, but we have a host of dev, so it's gonna take a minute.

But yeah, every time you make a change, especially indexes or anything unique, or anything like that, you have to run a migration. Some changes, and you can see right here, it's saying, a unique constraint, covering the columns (id.belongsToId) on the table Product will be added. If there are existing duplicate values, this will fail.

So this just tells you the database just assumed because I didn't put a unique index on it, that I could possibly have duplicate values, even though we wouldn't, because all IDs are unique and stuff, so that would have happened. But I'm gonna say yes, it's asking for a name, I'm gonna it's on my right one.

Once this is successful, it'll with the client, and then a client should not scream at us with TypeScript anymore, because those things should be unique. So let's see. And let me close it and come back, maybe. No, it's still screaming at us. Let's see, you have to write it in this special indexy way.

So this is a compound index or a joint index. So it's basically saying, we have a index between the Id and belongsToId. It's a joint index. Yeah, and in fact, I think if you have that, you don't even need the ID field, you can just say, id_belongsTo, and I don't know if it's an array, let's see.

I think it'd be req.params.id, and then req., user.id. No, it's not an array. Do you have to add them together? Let's look that up. There's got to be an object. So it'd be like, the Id is req.params.id, and then the belongsToId is rec.user.id. And now, we can search on that.

So now, it's unique, so we're searching on that index. And then you would do the same thing for the one up here. Pretty advanced stuff that they make easy for you, but sometimes the syntax isn't perfect.

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