Check out a free preview of the full API Design in Node.js (using Express & Mongo) course:
The "Exercise 10 Solution" Lesson is part of the full, API Design in Node.js (using Express & Mongo) course featured in this preview video. Here's what you'd learn in this lesson:

Scott walks through the solution to exercise 10. He also demonstrates how to create utility functions for generating the routes.

Get Unlimited Access Now

Transcript from the "Exercise 10 Solution" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Speaker 1: So the solution is actually very similar to what we did with the lions and tigers, it's why I walked us through that exercise on day one, is because we build up to this, it's the exact same thing. The only thing we did was we just replaced, cuz remember when we did lions and tigers, we actually started off doing the app.

[00:00:21] We had app.get and app.post and app.put. And then we refactored and we had subrouters, and then we had the router.get and router.post. And then we made a quick refactor and we used the router.route. Which just groups current routes together. And the only thing that changed from that to this is that now the functions that we passed into the lions and tigers are in the other files.

[00:00:48] That's the only thing that's changed. Nothing else has changed. They're just in another file now. And those functions, as we saw the last exercise, do the exact same thing as the functions in lions and tigers did. They just interact with the database now, and not an array of lions or tigers.

[00:01:09] So we just switched out two things, put them in another file, talk to the database, that's it. Everything else is exactly the same.
>> Speaker 1: So knowing that, if you were lost you could have either skipped ahead and looked at this, or looked back over the lines and tags and saw how we did the routing and saw it was very similar to this.

[00:01:26] So as far as requests to the root, we know that's getting up close because we don't need IDs for that. To create this resource, you don't need an ID because you're trying to create it. So let's do a get request of that. I'm sorry, a post request of that.

[00:01:41] You don't need an ID to do it. Get request for all of them, you also don't need an ID because you want all of them. So that's why register these two here, because controller.get finds all of them. And then controller.post creates one.
>> Speaker 1: All right. And then for the ones with IDs, we know that if we wanna get one, if we wanna update one or if we wanna delete one, we need an ID.

[00:02:15] So, that's how we registered these here.
>> Speaker 1: And as you probably see now, that's why the controller methods were named the way they were named. Cuz they were going with their appropriate verb with the exception of get1 cuz there is no get1 verb. So that's that, and then for the param, there's a controller.params function that we could run.

[00:02:43] So that's why it passed out in here. So router.param, it's important that this at the top for the at the top. This is down here. I can't guarantee that it will work the same, cuz technically this middleware but, I'm not sure if it's running off middleware, or if it's running off an event of seeing the ID, because express does eventing as well, like it'll fire this event for this route and this combination of verb.

[00:03:11] So, depending on how it handles that ID, the placing could be important. So, if you need it to happen first, just put it up top. Did everybody get what I say there? The reason I'm saying I don't know about the placing is because technically this is gonna be middleware.

[00:03:26] And what we know about middleware is that if it's registered first it will happen first. So, that's why I say put it up top. But also, it's expecting this ID property, and I know that these routes, the reason why when you called next inside of a middle word it only goes to one of these, and not all of them, even though they're siblings, is because it matches a combination of a verb and a route.

[00:03:50] It fires an event for that. So I'm not sure if it also does the same thing for this. If it did do that, then it doesn't matter where we put this, just like it doesn't matter where we put these. Doesn't matter what order we put these in, because they only happen on a certain combination.

[00:04:05] So I'm not sure exactly how Express handles that, so just to guarantee I'm gonna put it up here. Yes.
>> Speaker 2: There's a question, this is from a little while ago, but is the reason we extracted the controller code into its own files instead of inserting them directly inside the route so that we can use that code elsewhere by other routes and controllers?

[00:04:25]
>> Speaker 1: For higher level abstractions, yes. For the other reason is because, if you go look at our controllers, these are actually pretty small. Realistically, you start getting, if our models were bigger, which they are not, these controls would be much bigger, especially if we start getting into like you know, now we're caching.

[00:04:45] We're calling other services. We're doing other things. We're doing multiple queries. Nested queries. This controller file could be 100s and 100s and 100s of lines. And having that mixed in with the file that's also registering the routes is kind of confusing. And also now because these methods are exposed, I could probably test them now, cuz they're exported individually.

[00:05:08] I still have to mock out the requested response, and all this stuff. So we might wanna build an abstraction around that. But now these things are exported, and I can test them individually as units, whereas if I just put them all in this file inside this call back, it's gonna be kinda hard to test them.

[00:05:23] Cuz that call back never gets ran unless that route gets hit, and I can't hit that route until I call it. If I call the route, I may as well be doing integration testing and not unit testing. So, there's a few reasons I did that, organization, testability, and just sanity.

[00:05:45] Any other questions? So, all the files look exactly like this. The only difference between the other routes in the files is the path to where it's getting its controller. Everything else is exactly the same. So if we go look at Post routes, it's the same thing. It's just getting this controller here.

[00:06:02] Everything is the same. The code doesn't change here.
>> Speaker 1: So yeah, you might be thinking, I could just make a file or functions called create routes and it takes in the controller. And it just sets up in a router and it sets up all the routes on it.

[00:06:19] Yeah, you could do that, cuz it's all the same. You can totally do that,all the controllers and the same property names they all went to same routes, yeah we can just make a function called create controller somewhere else maybe in utility or something. Require that in here and just say create routes and pass in the appropriate controller in appropriate router, and you're done, you only write this thing one time.

[00:06:44]
>> Speaker 1: In fact let's just do it, so you can see what I'm talking about. So if we go into utils, and I make a new file called createRoutes, I can just say module.exports = a function that takes in the controller. Enter router. And all it's going to do is this.

[00:07:21]
>> Speaker 1: That's it. That's all it's gonna do. It's gonna do this.
>> Speaker 1: Now what I can do is, I can just get rid of the stuff. Keep the exports at the bottom, and i can just say var createRoutes= required
>> Speaker 1: And out API, or out of category, out API and the utils or utils and createRoutes.

[00:07:55] So now I'm gonna say yeah, this is createRoutes and so I'm gonna go ahead and invoke it right here, it's just too long of a line. So, I'll say, createRoutes(controller, router) and then that's it. And I can do this in all the files. I'll just about as copy this, these two lines put down here,ot rid of all this and just replaced it with that.

[00:08:22] Got rid of all this and just replaced it with that. It'll still work the same.
>> Speaker 1: Right, so it's an abstraction. So we just wrote it once here, and it does the same thing.