Skip to content

Updating Data

Adarsh Kumar Maurya edited this page Dec 18, 2018 · 1 revision

Introduction

In this module we're going to talk about updating data in our API. We've been following along building out a RESTful API using Node and Express and in this module we're going to implement the HTTP Put and Patch verbs that allow a user to update individual items. In Puts case we'll replace an existing item and in Patch's case we're going to update a specific part of an item. As part of that we'll also start to talk about Middleware. We've seen Middleware in use, but this time we're going to actually start to create our own route Middleware.

Implementing Put

What we have now is part of an API that allows us to get a list of items, post a new item back to our API, and then another set of routes that allows us to pull back individual items based upon a book Id. What we're going to do now is we're going to implement the Put verb, which basically means we're going to allow a user or a consumer of our API to replace one item with another item that they've edited. What we're going to do is come down here and we're going to do a .put and put, just like get and post, takes a function (Typing) with req and res. Now in order to update an item out of our MongoDB database I first have to get the item that I'm editing, so we need to do a Book.findById (Typing) and then the book Id. As a matter of fact, it's almost exactly this, so we're going to copy that and we're going to paste that right like that. The same thing, if I have an issue here I'm going to send back an error. If I do have a book though we're going to have to replace the contents of that book with what has come back, so we're going to do book.title = req.body.title (Typing), author with author, genre with genre (Typing), and read with read (Typing), and then we're going to do a book.save to save our changes.

Testing Put

Now back over in our Postman client we can do a quick get just to make sure that we're up and running and everything's compiled and everything's good. Now if I come down here to this book that we added, the My New Book, and I add that Id to the end and I do another get, now I see we just have our one book, and that's all fine, we've done that before, but now I want to do a .put, which basically means anything I change in here is going to change down here up to including if I do this the new result should be empty, and that is expected behavior. If the new put contains empty fields it should just return those empty fields, so we are updating and everything's working. If I want to put these items back maybe with a little change, let's give this a title (Typing). Now remember we're not doing anything with Id, so we can delete those, and hit Send. Now we see that we are actually updating as we expected, so let's go back and do a get, Send, and you'll see we are working. Now this _v is something from MongoDB that's just coming back and that's a version indicator that we're not going to worry about at all. Just ignore that and you can pretty much just pretend that doesn't exist until you get really deep into MongoDB stuff, so for right now just ignore that. They'll come back on the gets because it's something that Mongo does on its own. Now that we have put though let's go back and let's implement a patch because what if I just want to update the false to true? I don't want to have to send the entire contents of that book in order to update that one thing, I just want to be able to do a put or a patch, set that to true, delete everything else, and have that update my book to be true, so let's go back over, let's do a patch, and we'll see how that works.

Middleware

Now when we come back over to the code and we start to do our .patch (Typing) the first thing we're going to do in our function is do this book.findById and we've done it once there and we've done it once there and we're about to do it again, and so the pragmatic programmer in you should be screaming we're not supposed to repeat ourselves over and over again, and we repeat once, okay, if we repeat twice we need to stop and do something about that, and the way we're going to do that is by implementing something called Middleware that's going to inject itself in between the call and this route. Now to get a quick idea of how Middleware works let's look at this real quick. A client sends a request and that request is handled by the route in the router and then that router is going to send a response back to the client. Now when we're using Middleware what's going to happen is we create a Middleware, so that when the client sends a request this Middleware is going to drop into the middle of that request and then, after it does its piece, forward that request onto the route, and then the route will send a response back to the client, so what we're going to do right now is we're going to create this piece of Middleware that's going to intercept to the request, go and find the book by Id, add it to the request, and then forward that onto the route. Let's look at what that would look like. Now the way we are going to be doing it, we're going to do Middleware by the route, so here I'm just going to do bookRouter.use and that's the signal to say hey, I'm about to do some Middleware, and I'm going to use only for the route that has a book Id, and it takes a function that takes the normal request response and a next, and what next is going to do is tell it to pass on to the next thing that's to be done. In this case, since we only have one piece of Middleware, it's going to move onto this .get or this .put. If we had more Middleware it would then move onto the next piece of Middleware. To implement this Middleware all we're going to do is we're going to take our .get function, this book.findById, and we're going to copy that. Actually we'll just cut it altogether and then we'll --- paste it in there, so in our Middleware it's going to do a findById and it's going to find the book Id. If there's an error it's going to return the error. If the book exists we're going to add it to the request, so req.book = book, and what that's going to do is it's going to then make it available to everything down stream from here, and then we'll call next. Now if the book isn't found we're going to return the 404 (Typing). Now once that's done we have our request, it now has a book, so down here in our .get all we really have to do is do a res.json req.book because if there is no book, then it won't ever get here. We'll return a 404 up above it, and if there's an error we'll return that too. If we get to .get, then everything's been good. We've found a book from the database and we're ready to return that book back up, so in this case in our .get we'll just do a res.json and send the book back. Now the .put works the same way, so I don't need my findById, I don't need my if(err), I don't need my else (Typing). All I need to add is a req. in front of book (Typing) and now basically what it's doing is everything that's in req.book is being modified with whatever's in req.body, and then we're going to save that and then we're going to return it. That's all it takes to make that happen. Now we have a .get and we have a .put for our router. Now what we need to do is what we originally intended to start doing is add our .patch.

Implementing Patch

Now given the patch put together is just as simple as doing .patch (Typing) with the function req and res (Typing). Now remember our book is coming out of req.book and we only want to update our req.book with the items from req.body that are there, so if req.body.title (Typing) exists, then we want to update req.book (Typing). Now you could probably imagine this will become very painful very quickly, so we're not going to do it this way at all, this is silly. We instead are going to use the for in loop (Typing). What the for in loop means is that for every key in req.body it's going to give me that key name, which is extremely useful for navigating through your things like this, and so we actually can just do for var p in req.body, req.book, sub p = req.body sub p. That way we are assigning everything that's in req.body over to req.book. Now the only caveat to that is that we don't want to update the Id. That's a requirement based on what we're doing, so up here at the top we're going to check and see if req.body._id (Typing). We're going to delete req.body._id. Alright, now that that's done and we've looped through we need to do a req.save or req.book.save (Typing) and if you look up here this is not right. That's not asynchronous coding and we're going to fix that right now. If you come back down here we're going to pass in a callback and do the same if(err), so if we have an error we're going to send back an err else we are going to send back the book. Then we'll do a res.json(req.book) just like that and we'll do this same thing up here (Typing). Alright, now that we've got our save going in both places, we've got our patch, we've got our put, we've got our get, it looks like we've got most of the verbs covered. Let's go ahead and pop back over to Postman and try it all out.

Testing Patch

Now that we have all that going let's run a couple tests and make sure everything's working. I'm going to click Send on this get and you'll see I have a book that's returning authored by Jon Mills, titled My First Course. It's also read false. Now if I do a patch on this all I should have to send is read equals true and it should only update just this one item, so if I click send you'll see I did a patch over here, and I've returned back the whole book with just read equals true, and just to make sure it actually worked we can go back to the get, click Send, and there you go, it all worked. Now the other thing we want to try is making sure that I can't send the Id, so if we do a patch on this again, and I update the Id (Typing) to something different, let's just say ssss, and I send that, notice it did not update the Id, so if I go back to the get, Send, Id is not updated, so that worked out nicely for us. That one for loop was all we needed to get our patch done.

Implementing Remove

Alright, there's only one left to implement and that would be delete, so we're going to do a .delete, and this one's going to be really super simple. Get your function (Typing), req and res, and in this we're just going to do a req.book.remove, and what that's going to do is take whatever book was found up in our Middleware and remove it. Now just to make sure everything's good we're going to do our callback, so we're going to return the function with err (Typing). If in error we're going to send our status, otherwise, if it works we don't have a book to send back, that doesn't exist anymore, so we're going to do a res.status (Typing) and we're going to send back a 204, which means removed, and we're going to send the message Removed (Typing), and that's all there is to implementing the remove. Real quick let's go check that out and make sure that worked. Alright, so I have this one, My First Course, it's read, now I just want to remove it, so let me click Delete, and we are going to send that and I got a 204 status, No Content, that means it doesn't exist. What I want to do now just to make sure, is we'll do our get, we got a 404 no book found, so that was it, and that was all it took to implement that remove verb.

Summary

Alright, so in this module we finished up the verbs that we're going to use as part of our RESTful API that we're building with Node. We've implemented the put and patch verbs to replace an existing item and update part of an existing item, so that we don't have to send back and forth the entire pay load of an item, we can just send bits and pieces of it, and lastly we looked at how to remove an item using the HTTP delete verb and we figured out how to do some Middleware to help prevent us from having to replicate that findById code over and over and over again. Now at the end of this module we've successfully implemented all of the RESTful verbs, so we've done get, post, put, patch, delete, all those are done, and they're in place and implemented in our code. From here on out we're going to look at things like HATEOAS, our hyper media that we're going to implement into our API, and we're going to look at some automated testing.

Clone this wiki locally