
Lesson Description
The "Update Habit Controller" Lesson is part of the full, API Design in Node.js, v5 course featured in this preview video. Here's what you'd learn in this lesson:
Scott explains how to update a habit by separating tag IDs from the request body, running a transaction to ensure integrity, and checking authorization before saving changes. He also covers managing tag associations, returning proper responses, and handling errors during the process.
Transcript from the "Update Habit Controller" Lesson
[00:00:00]
>> Speaker 1: We have a single habit, which is mostly what we just did, but instead of find many, it's just find first It's literally the same thing, so let's do something a little more interesting
[00:00:00]
And let's update a habit Let's do that So if we go back to our habit controller, we'll say export const update habit Same thing, req and response
[00:00:00]
Dedicated request First response, OK, so for this one Pretty much similar to inserting, but instead of calling it insert, we're gonna call it set, which set is basically how you would update something, I guess that's the best way I can describe it
[00:00:00]
So, and because of tags, we're gonna do a transaction because if something fails, we want to make sure we undo all of it
[00:00:00]
First thing is we want to get the parameter and the ID because this is going to be updating a habit, and we're assuming this is gonna be mounted on a route that has a slash ID in it, so I can get the ID from req.params.ID
[00:00:00]
I could type this if I want, but I'll just assume that the ID is there Then let's separate tag IDs from the req.body from everything else
[00:00:00]
The reason we're doing that is because our habit in the database has no concept of tag IDs, but we're allowing you to send up some tag IDs that you might want to associate with an existing habit
[00:00:00]
So we spread and take those two things out because they're gonna be operated on two different tables So you can send tag IDs, and everything else is gonna be considered what updates you want to apply to this habit
[00:00:00]
We'll start our transaction, so result goes to await db.transaction Get our transaction object here, and it's just the same thing we've been doing
[00:00:00]
In this case, we'll say this will be the updated habit, and it's gonna await this transaction's update So we want to update on the habits table
[00:00:00]
We'll call set, which will just apply the partial updates you want here and not override what was there We'll set whatever these updates are and then update the updated_at field to be now
[00:00:00]
We don't want to do this to every habit, only the habits that match this call So we need to check not only the habit ID but also ensure the user owns this habit
[00:00:00]
This is authorization Are you authorized to update this habit Yes, because I'm the user ID on this habit, and you know my user ID because of the authentication middleware
[00:00:00]
The first check is the habit ID equals the ID from the route The second check ensures the habit's user ID equals the signed-in user's ID
[00:00:00]
If you didn't do this second part, anybody could update anybody's habit if they knew the ID That's a big security flaw
[00:00:00]
Imagine being on Twitter and anyone could post on anybody's account If the update doesn't find anything matching the where clause (which Drizzle won't error on), we'll throw a "Habit not found" error or return a 401 status
[00:00:00]
We'll then handle tags by deleting existing tags for this habit and adding new ones if tag IDs are provided Finally, we'll return the updated habit from the transaction, send a response with the updated habit, and handle any potential errors
[00:00:00]
Regarding transactions, Drizzle handles commit and rollback automatically If an error is thrown anywhere in the transaction, it will automatically roll back
[00:00:00]
If it reaches the end of the function, it will commit To add this to the habit route, we'll use a PATCH method with an ID parameter
[00:00:00]
While input validation would be ideal for better error messaging, in this demonstration, we'll keep it simple This pattern is very similar across different resources, and you could potentially write a generic function to generate CRUD operations for different resources.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops