This workshop will be retired on May 31, 2020.
Updating and Deleting Reviews7:09 with Pasan Premaratne
Let's wrap up the project by implementing the last two routes for updating and deleting reviews
To update the review, we're going to implement logic that looks 0:00 much like the last get route, but includes one additional operation. 0:03 Decoding a review object that's included in the body as JSON. 0:07 So down here, we'll say this is a PUT route. 0:12 The path is api/courses/courseId/reviews/reviewID, 0:18 and this path is going to update the review. 0:25 We're going to do the same thing we did in the last route handler. 0:33 And that is to make sure that there's a review object 0:37 associated with the course specified that matches the review ID specified. 0:39 The URL is the same as the get route, so 0:45 we can actually just copy everything over from that top line. 0:47 And we'll just need to change the method to put. 0:53 We'll start in here with a flat map call, and 1:00 use the method signature that takes two operations as arguments. 1:02 For the first, we'll fetch the course object whose ID is specified in the path, 1:06 like we did in the previous route. 1:11 For the second, we're going to decode the review object included in the JSON body. 1:12 So this is return try flatMap to, eventually, a Review.self. 1:19 So here, we're going to call req.parameters.next(Course.self) to fetch 1:24 the course from the database that is indicated by that ID parameter. 1:30 And for the second future, we're going to decode the review object. 1:35 So request.content.decode(Review.self). 1:38 Both of these are passed into the callback, course, updatedReview. 1:47 We also need to retrieve the int value specified in 1:52 the path to use as a review ID that we can filter on. 1:56 So let reviewId = try req.parameters.next(Int.self). 1:59 Next we need to query the course object to match the review. 2:07 And we can copy-paste this bit from the previous route handler. 2:10 So we'll get everything in here, so everything from the fetch and 2:14 the filter operation, and we'll paste that in here. 2:19 Now in the last route handler, the one I just pasted in, we called map on this, 2:23 since we wanted to return just the review object. 2:28 In this case, we need to update the review and save it. 2:31 The save operation resolves into a future, and since we're returning a future, 2:34 we want here a flatMap to Review.self. 2:38 Now inside the body of this closure, we'll do what we did last time and 2:44 assert that this is not a null value by using this guard check. 2:47 And then once that's taken care of, 2:51 we'll update the filtered review with the information from the decoded review. 2:53 So we'll say filteredReview.rating = updatedReview.rating. 2:58 And then, filteredReview.comment = updatedReview.comment. 3:04 And then we can return the filteredReview and save it in the process. 3:09 Okay so this one was probably our most complicated one yet, 3:15 let's do a tiny recap. 3:19 So we started by calling the flatMap function with two arguments. 3:20 Each of the arguments we've provided are lines of code, so right here and 3:24 right here are lines of code that resolve into futures themselves. 3:29 When all of them complete their passing as arguments into the callback closure. 3:33 So in order, we've specified that we want to fetch the course object whose ID 3:38 matches the one in the URL. 3:43 And then we want to decode the JSON in the request body into a review object. 3:45 Now we need to double check that the review we fetched is one associated with 3:51 the course. 3:55 So next, we use the integer value as an identifier and filter over here. 3:56 So of course, our review is query on request filter. 4:01 We do that to match against the fetched review object's ID. 4:04 Now this operation also returns a future, so to this, we chain another flatMap call. 4:08 Because we want to use the result of the filter operation to update the review with 4:13 the decoded one, and finally call save on it. 4:18 So to check this out, you should pop over into Postman after building and 4:21 running this. 4:24 You should get a 200 status code on the put request, and if you compare 4:25 the response body, you'll see that the review has actually been changed, cool. 4:29 Now once we've handled the put request, the delete is fairly easy. 4:33 The teeny difference, which we talked about earlier, 4:37 is that since we don't have a model instance to return in the response body, 4:40 we're going to send a status code back to indicate the delete operation worked. 4:43 I'm gonna copy this comment, and 4:48 then go down here, put it in there, and this is a delete. 4:51 And the path is the same, except this is going to delete a review. 4:56 Again, the URL is the same, and so we can copy-paste this method signature. 5:02 Except we're going to change it from router.put to router.delete, 5:08 and this is going to return a future HTTPStatus. 5:15 We're going to carry out the same operation here that we've done several 5:20 times already. 5:24 And that is to assert that the review in the URL is actually part of the course. 5:25 Now to make this easy, since you know what we're doing, we're going to copy-paste 5:30 the body from inside the get request, so this entire thing. 5:34 Right, we're gonna put that in here, and we just have to make a couple changes for 5:40 this to work. 5:44 First, we're returning a future encapsulating a status code. 5:45 So this needs to flatMap to HTTPStatus.self. 5:50 Second, the inner method call chains a map to the review type. 5:55 We need to change this to a flatMap, and 6:01 we need to change the type to HTTP, Status as well. 6:04 Finally, we need to return not the filtered value, but 6:11 the result of transforming a successful delete operation to a status code. 6:15 So we'll delete this on request, and then transform that to HTTPStatus.noContent. 6:20 So let's walk through this final operation. 6:27 We start by fetching from the database the course object specified in the path. 6:30 When this resolves, we query the course over here for all of the review objects. 6:35 And then filter out and assert that the review object whose ID 6:40 was specified in the URL is included in this set of reviews. 6:44 If not, we throw an error, if it does exists, we delete it. 6:48 And when this operation successfully resolves, 6:52 we transform that into a no content status code. 6:55 So build, run, and switch to Postman. 6:58 The entire request collection should now run successfully. 7:01 Including a 204 no content status code for this final operation. 7:04
You need to sign up for Treehouse in order to download course files.Sign up