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

Review of the middleware solution to parse the URL and protect the API with authentication middleware.

Get Unlimited Access Now

Transcript from the "Solution: Middleware" Lesson

[00:00:00]
>> Scott Moss: So let's talk about the global middleware. So inside this middleware file, if you use the bodyParser. You can use them in any order you want, but basically, using the bodyParser, you can say app.use, and you can setup that bodyParser middleware like this, urlencoded({extended: true})). Basically, what this is allowing us to do, this is middleware where this middleware is going to format the query string for us, basically.

[00:00:27] If you pass in the query stream like, this is your API.
>> Scott Moss: Like this, right? thing=1, other=two, stuff like that. It'll format that so we can access it on request.params.
>> Scott Moss: That's what it's doing. So you wanna be able to do that. Extended just means some extra rules that they'll add for free.

[00:00:55] bodyParser.json is just basically anything that's posted or put to the API gets treated like JSON parsed and then given to us in req.body. This is where req.body comes from. Without this, we don't have req.body, this is very important. So that's the global middleware. It is already attached globally here, so I put setupMiddleware, I passed app in, and it's like a mix-in, right?

[00:01:17] It just mixes the middleware in. It doesn't need to return anything. I mean, you can return the app if you want, but it doesn't really matter. app.use just mixes it in, so it's up to you. And then down here for the API I used. Yeah, so I didn't go in and specifically say you could do this, but if you experimented, you could've attempted to do it.

[00:01:39] But basically, if we go look at the, where we at? There we go. modules/auth, so we're gonna use the auth stuff here. I have an array down here that has two middleware inside of them. One is called decodeToken, one is called getFreshUser. You don't have to use getFreshUser, all you have to use is decodeToken.

[00:01:59] This is for later when we get into models which I think is next. Because in order to understand what getFreshUser is doing, you need to understand how models work. So I left it out on this exercise, but if you just put the protect array in there, you're totally fine.

[00:02:10] But then that's what I'm saying is middleware can also be an array because we can come inside of here. And we can pass an endless amount of functions. It doesn't matter, they're all gonna run serially. So if I wanted to run this function, if I can type, there we go.

[00:02:28] I've got so much adrenaline from the bar fight. [LAUGH]
>> Student: [LAUGH]
>> Scott Moss: And I run this function, you can run as many functions as you want. Or you could just pass in an array, which is exactly what protect was. It was an array of middleware.
>> Scott Moss: So you can pass in an array which cleans things up.

[00:02:44] So if you need to share middleware stacks across different route definitions, you can do that. So, I want this chain of middleware shared across those routes. I'm gonna put them in an array so I can just put that array in different places. Versus writing them all over again, over and over and over again.

[00:02:58] You can also compose your middleware. So you could have your middleware compose themselves, which is something different, but what that will look like is basically, instead of returning an array of middleware, I would have a middleware that calls another middleware that calls another middleware, that calls another middleware.

[00:03:14] And I would just place that one entry middleware as my main middleware. It's kinda crazy, but yeah, you can do that. It depends on how you wanna do it. You want an array, you wanna pass them in line. You wanna do anonymous functions, you want a composable middleware.

[00:03:29] Express doesn't care, do whatever you want. I chose to be slightly explicit and used the arrays. Composable middleware is a little advance, but basically, you're taking middleware and you're calling next and you're extending it to another middleware right inside the middleware which is kinda crazy. If we just take a quick look at what's going on here.

[00:03:51] Who here has used JSON Web Tokens? Okay, JSON Web Tokens, at the end of the day, it's a unique string that's signed on your server. It's a unique string that basically when decoded turns back into the object that was signed on. So basically, if I have an object like, I have a user whose id is one.

[00:04:12] If I get a JSON Web Token from this, I might get back some crazy looking string here, right? That string the client would use to send request to the API. The API would will take that string, decode the token and verify it, and it would get back this object, right?

[00:04:30] It'll get this object back. And then with that object I went, let me go see there's the user ID I wanted here. And that's how we do authentication. It's a stateless way to do authentication. So that's what we're doing here. And basically, this decodeToken, what it's doing, it is checking for the token in the headers or the query string.

[00:04:50] And then it runs this checkToken middleware, which is something we have not created because it's given to us by expressJwt. You pass in the secret, the secret is how you sign the token and also how you decode the token.
>> Scott Moss: And then refresh user all it does is, after decodeToken runs this function right here, checkToken, it attaches that object to the req.user.

[00:05:15] Whatever the value of this token is, it's going to attach it to a req.user. So inside of getFreshUser I can get req.user.id, look in the database to see if there's a user.id in there. If it's not, you're unauthorized. If it is, continue to test if that's a req.user and then call next.

[00:05:34] So it's a little complicated because we haven't talked about database queries, and that's why I don't want to talk about this, but that's what's happening inside a getFreshUser. This will make more sense when we go back over databases in the next one, and you can also look at the comments of exactly what's happening here.

[00:05:46] It seems complicated, but it's not as complicated as it looks. It's just a lot of comments here that makes it look really big, but it's not. So that's what that's doing. So to verify that, now that I have protect in front of here, if I try to hit the API, if anybody's tried this so far, you'll probably run into a problem, right?

[00:06:03] Has anybody got to this point? And what's the error that you see?
>> Student: Unauthorized.
>> Scott Moss: Right, you'll see UnauthorizedError and it will say, No authorization token was found, right? Yep, that's exactly what it was supposed to do. There was no authorization token found. It completely-
>> Student: Would that error be handled by an error handler, though?

[00:06:23]
>> Scott Moss: Should that error be handled by error handler. Well, it depends on where you put your error handler. For me, no, my error handler is not here. I don't have a global error handler. But if you setup a global error handler, cuz we'll see where I put my error handler.

[00:06:36] But if you setup one here, app.use, let's make one here. err, req, res, and then next, even though we probably never use next. Then I can console.error for error. So say err.stack, and then res.json, or status(401).send.
>> Scott Moss: So you can do that. And let's try it again.
>> Scott Moss: So now, if I run this, yeah, now it will.

[00:07:19] This is like nope, not gonna happen. And you need to see a console.error.stack just to get the stack of it for my login purposes, but yeah, it totally got handled here. But where I put my error handling, I made error handling specifically for the API router. I think you would probably handle errors differently for your API routes than you would for any other routes.

[00:07:42] So the error handle that I made was specifically for apiErrorHandler. So I mean, it does the same thing. Calls the stack, 500, but the difference is where I placed it. Because I want it to log for the API, I place it on the restRouter, here, at the end, all right?

[00:07:59] Another thing to mention about error handlers, is they have to go at the end. If I did this, it would never run, right? Because the errors bubble up. When an error's thrown in here, it's gonna be like, cool. Cuz you called next, right? When you called next, you threw an error in.

[00:08:14] You sent it to the next thing. But if this is before it that means it's not after it. Therefore, you cannot go next to it. It's previous, right? So it needs to be next in order for you to bubble the error up. So you need to make sure the error handler's always at the bottom.

[00:08:29] Otherwise, if won't work. So if you did that and you're like, why this is not working? It's probably cuz you put it at the top. I know people will probably get often like, what is this? It seems cool, let's go over this. When we got time tomorrow, we can go over this cuz in fact, depending on how we do it with GraphQL tomorrow, we may or may not use it this way.

[00:08:52] It's kinda hard to explain with GraphQL, but yeah, we can get into this in more detail. There's some features here like disableAuth that I'm not talking about, but we'll get into that later today as well. But yeah, auth is not as hard as it seems. I mean, at the end of the day nobody's stuff is safe.

[00:09:07] [LAUGH] Nobody's safe at the end of the day. Let's be real.