This course has been updated! We now recommend you take the API Design in Node.js, v3 course.
Transcript from the "Solution: Express Routing" Lesson
>> Scott Moss: If you look at the list of challenges here, we have to look at the User router as a reference. And you can follow it all the way down. Now when I say follow it down, there's two nested routers there, so follow it all the way down to the source.
[00:00:10] And the source is basically where you're responding to. Which if you would have found out, there's literally no response there. But look at that, build out the song router with all the routes very much like the User router. Build out the playlist router, with all the routes very much like the User router.
[00:00:24] Connect the song and the playlist router to the rest router. And then eventually collect the restRouter to the base express app on the /api path, right? So let's check that out, see what we've got here. I'm just going to check out, to save some time, because I love live coding, but let's get through this.
[00:00:43] Some solutions here, and then I can live code some stuff that's not here.
>> Scott Moss: There we go. Nice, so first things first. Let me get rid of this stuff that we just did last session.
>> Scott Moss: Okay, first things first is we need to connect our restRouter to our app.
[00:01:09] And that one's pretty simple, after I use, we mount it, this is what, when you hear people say mounting, this is what they're talking about. We're mounting this route at this path here. And we're doing that before our catch all that I have here. By the way, I have this catch all here, this by no means is me saying you should have this in your app, okay?
[00:01:28] If you don't have a route, you should definitely throw an error, a 404 or something. I'm just having this so it's for development. But yeah, and if you're building an express app that's serving a single page application, you'll most likely just send back the index page. So this is like another thing you would have to do as well.
[00:01:46] But you shouldn't be serving on a static, you shouldn't be doing a front end app on the Express. You should just serve it on the CDN instead, but anyway. So yeah, we mounted it at /api, got the restRouter. Let's go take a look at the restRouter here. Any questions here by the way, about this part so far?
[00:02:04] Okay, the restRouter, if we go take a look at the restRouter, all the stuff that you need is already imported. And what you saw was you had just the user mounted at /user. So we're just gonna go ahead and mount the songRouter and the playlistRouter on the appropriate paths as well.
[00:02:19] So we got /song /playlist, and the important thing to remember here is, one order. So I guess in this case, order doesn't really matter, cuz they're completely different paths, right? So it doesn't really matter, right? They would matter if they were the same path. The other thing is that the usage of use, if we didn't use use here, we have to say something like this.
[00:02:41] We'd have to say like, let's say I want to mount some stuff on the restRouter for song. I'd say restRouter.get('/song'. Or just '/song', then I'd have to be like, /song/router, it would be very tedious to do all that. So use the .u so it's just like, hey, anything for /song just delegate to this router.
[00:03:05] I don't care, I'm just passing it through. I don't really care, it's not my job, I'm just passing it through right, so that's that. You can do the same thing to playlistRouter. So let's go take a look at the userRouter. And notice the typo here, we definitely don't want a createOne on delete, you should want a deleteOne.
>> Scott Moss: But notice, I walked through this before the example, but the param, when we're talking about middleware, which is, I think that's the one we're talking about actually, this is gonna make more sense. But this is popping off the parameter of the url, right? So if we created a URL or route that's like /api/song/:id, that's how you do parameters.
[00:03:52] Then it's going to grab that id and it's going to pass it as an argument to this function. And then that function will do whatever it wants. The function, normally what it will do is look in the database for that id resource, attach it to the request, and send it down the line, right?
[00:04:07] Because if you're coming in if you're looking for a /api/song/:id, and let's say this is a get, let's say you did a get to this. Say you did a get there, this is not the thing that's going to respond. The thing that's going to respond is the route that you set up for this URL, which is song/:id, which in this case will be something like down here.
[00:04:28] But this one runs first, so this one would run first, grab the resource from the database with the appropriate id, attach it to the request. Send it down the line to the one that actually matches this, which will be down here. And then that would have access to the object that was attached to the request, and then it can respond appropriately.
[00:04:47] Right, and that's how that will work. And you can do that as much as you like, middleware is as much as you like, but just don't abuse it. So we got this in a userRouter, so if we go look at the songRouter, we should see it's pretty much be the same thing, right?
[00:05:07] We use the .route thing again for shortcuts, otherwise we'd have to use the route over and over and over again. This is just shortcuts. The reason this stuff is mounted like this is because I'm following REST right? So basically, I mean who here knows what REST is?
>> Scott Moss: I don't think anybody knows what REST is cuz it's not a thing right, it's like, yeah, it's a thing, but is it really a thing?
[00:05:34] There's like conventions just like, REST should be like, but there's really no convention. They have like standard API and their swagger and all there's all this stuff but like, really what is REST? Everybody, at the end of the day, has to denormalized their REST to do something crazy.
[00:05:47] You gotta attach these query strings, you gotta do these crazy stuff because eventually what you have to do. What you find out is that you build an app, whether it's a mobile app or a web app, and you find out is that that app needs data completely different in the way REST is designed.
[00:06:01] It doesn't need it like this, it needs associations, it needs nested structures and REST doesn't satisfy that. So what you end up having to do, you optimize for the client especially if it's a web app. You want the client to be optimized. So therefore, you don't want the client making multiple calls to get associations.
[00:06:17] So you fix the back end, and now you don't do REST anymore. Now it's just like, well, now we made this one special route just for this page. And it's like okay [LAUGH] what is this, right? So I mean really, what is REST? But I guess the way you could think of it is, it's just a structured way that we can define our routes that can interact with our resources taking advantage of HTTP verbs.
[00:06:38] So if you use the verb get, that means you want to get a resource. If you use the verb put, that means you want to update a resource. If you use the verb post, you want to create a resource. If you use the verb delete, you want to remove a resource.
[00:06:54] And then options verb is for cores. And then as far as the resource string is concerned, that's just gonna be slash, wherever your API is, right? You got some business logic here, and you might see something like this. Typical, you'll see something like api/v1, nobody has a v2.
>> Speaker 2: [LAUGH]
>> Scott Moss: [LAUGH] Nobody has a v2, it's always v1. They're over optimistic about that new API they never build. It's always v1, and then the resource name. They'll be like, the name of the thing. So in this case, we might have user. And then typically what you do here is you would do get and put to this.
[00:07:31] So if I did a get request to this URL, that means I wanna get all the users, cuz I didn't specify an id. If I did a post request to this URL, that means I wanna create a user, right? But now, if I put an id here, and I did a get request to this?
[00:07:46] It means, I wanna get the user with this id, right, so not all users. You couldn't do a post here, because you could not create a user with this given id, so that wouldn't make sense. But you could put a put here, right? So a put, what it means, I wanna update the user with this id.
[00:07:59] And you can also put a delete here, as in I'm gonna delete this user with this id, right? So that's basically REST, or what REST should be. It's supposed to be stateless, it's supposed to be all this. But at the end of the day, nobody really knows what it is, and nobody wanted to admit it.
[00:08:17] Really that was it, I mean Rails came out, Rails was like, here, we're doing REST, everything's RESTful resource and it's great, you can do CRUD. That's great for a todo app that literally only does that, but what about a component that like does all types of crazy stuff?
[00:08:29] Like this is just not gonna work. But we'll learn about how to fix that tomorrow. Cool, so this is what you have to do for the songRouter. And then the playlistRouter is very much the same thing. As you can see, this is like a benefit of REST I believe, because you're pretty much doing this, it doesn't matter the resource, they all need the same endpoints, right?
[00:08:52] I mean, for user, you probably don't wanna be exposed in creating a user, you wanna go through authentication for that. But for other resources, yeah, it's the same thing. You get one, you can delete one, you can create one, stuff like that. So that way you can see that a lot of this stuff is redundant.
[00:09:07] We could have abstracted this to a whole other level, and just passed in a router and registered the routes for it that way with just one function. Which is what we're doing with some of the other files we'll get to soon.
>> Scott Moss: You have a question?
>> Speaker 2: Mario's asking, so in the case with the callback in the param function does the job the song is going to be available in the routes that match later?
>> Scott Moss: Exactly, yep, so the param is gonna attach it to the request. And that same request object is passed down to the next handler. So yeah, if you mutate the request object, it's passed down the whole request. You can think of it as a per-request cache, basically. It's only there per request.
[00:09:45] You don't have to be afraid of having two different request's data on the same request object, which would be very dangerous, all right? It's only per request. So yeah, mutate the request object, pass it down. It's available onto whatever handler comes after it, until you respond.
>> Speaker 2: You just have the createOne again for deleting on the other two?
[00:10:05] I don't know if that matters.
>> Scott Moss: Yeah, yeah, they're all type, hold on.
>> Speaker 2: It does, but I don't know if it matters for the sake of the course.
>> Scott Moss: It definitely matters. I'm sure my test will fail. Cool, well let's dive into the next thing, which is going to be Controllers and Responding.
[00:10:22] I thought middleware was next. Okay, so we're going to Controllers and Responding. So if you've got all the way through this example, actually, let me write it just to show you. Cuz I'm sure people were freaking out and people online probably didn't hear me when I finally revealed that this is what should be happening.
[00:10:35] But if you run this, you got everything working, it doesn't break, everything's good. Right, you go try to test out your thing. Let's go test it out, let's see. We can do this nice trick right here, that's awesome. And then you can do /api, and then you wanna get all the songs, and you hit enter.
[00:10:55] And nothing happens, it just hangs. That's not a bug or anything, nothing's coming back. I should expect something back. Eventually, this is gonna error out, it's gonna time out. That's intentional, did anybody do some digging and figure out why? Yeah, why?
>> Speaker 3: Cuz all the methods are empty in the query.
>> Scott Moss: Yeah.
>> Speaker 3: Query.js.
>> Scott Moss: All those methods in query.js are empty, and those methods that you're talking about are called controllers. All the controllers are empty, there's nothing in here. Now I'm doing some pretty crazy stuff in here, kind of. But it's not too advanced and I wanted to do this because I wanted to show how you can generate things based off like shared logic.
[00:11:42] Because it is REST and because we do have this path and everything's gonna follow the same convention, every single resource is gonna have a create, read, and update, and delete. It's gonna have CRUD on it. We can just do the exact same controllers for now by default on every single resource until we don't, right?
[00:11:58] There's gonna be times where we have to do associations and we need a different controller. But by default, yeah, they all do the same thing. Creating a song is the same thing as creating a playlist, they just take different parameters. But the logic is exactly the same. So that's why this follows here, this allows us to take any model when we get to models and then do that thing on that model.
[00:12:18] So that's what we're gonna do next.