Check out a free preview of the full API Design in Node.js, v3 course:
The "Custom Middleware" Lesson is part of the full, API Design in Node.js, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott codes some middleware, and demonstrates how to pass the middleware to the controllers through the use of the next() method.

Get Unlimited Access Now

Transcript from the "Custom Middleware" Lesson

[00:00:00]
>> Scott Moss: So, what we're gonna do, is we're just gonna create some middleware here though and see just how familiar it is to what we've already done so far. So far, we've created these small routes and we have these call back functions here what I've called controllers because they're basically the last function that needs to run on this route.

[00:00:16] Now, we're just gonna create some middleware. And to do that, it's the exact same syntax as the controllers. There just functions that take a request and a response. And then they run some action. So I'm just gonna make a middleware here and I'm gonna call it myLog or just call it log.

[00:00:37] So it's gonna take a request. It's gonna take a response and is just going to log, logging. So, down here these controllers we have the ability to do rest.send, rest.send, that's what we have been doing. That's gonna end a request and that's gonna send back a response to the client.

[00:00:59] Well like I said the middleware, the intent is to not do that, although we can. I don't wanna end the request and send back a response to the client, I wanna continue moving forward. So that's where that third argument comes in that we haven't used. We just call it next.

[00:01:15] But it's basically just a function that when called, executes the next middleware that's after it, that's all it's gonna do. So this is where Express ties the middleware together. So by calling the next function, I'm basically saying, okay, I'm done here, go to the next one. Whoever's next, because this log function doesn't know who's next, doesn't know who's registered after it.

[00:01:37] But whatever is next in the stack Run that function and that can be another middleware. It could also be a controller. It could be anything. But it doesn't really matter cuz it doesn't know. So I'm just gonna call next like this. If you call next with an argument, the argument is gonna be treated like an error and we'll talk about that when we get to error handling.

[00:01:57] Normally, just call it next with no arguments. And unless you have an error that you wanna pass along and don't wanna handle in this middleware. So for instance, this was an authentication middleware. And there's an authentication error, you could just, in the request right here, what the rest.send or rest.status whatever you wanna do.

[00:02:16] Or you could pass that error along with next. And then later on in your application have an error handler kinda like catches it and deals with it there. So it's up to you. But for now, we're just not gonna pass anything. And then, all we gotta do is just add the log to our route definition.

[00:02:32] So you can see, I just squeeze it in here after this route. And that just is basically letting me run this middleware function, before this controller runs. That's one way I could do it. The benefits of doing it this way is that it's only gonna run for this route.

[00:02:50] If I wanted this log functions to run for the entire server, I could use an app dot use log. Now it's gonna run for everything. Very similar to what we have up here. Another way I could do it is I could say I want to pass an array of middleware.

[00:03:13] There's if I had log here like three times or other middleware, I could do that as well and that's gonna run all of these in order before it executes the controller. So there's like a lot of ways you can actually register middleware and execute it those are just three.

[00:03:26] There's other ways you can mount it them at different paths you can mount them at different sub-routers when we get to sub-routers there's a lot different configurations with middleware. But at the end of the day a middleware function is basically the same thing as a controller function they have the exact same syntax the exact same capabilities.

[00:03:41] The only difference is that they are intent. The middleware is intent is to not respond is to mutate, whatever and pass on in a controllers intent is to respond. That's it. But they can both do either. But at the end of the day if you don't respond user services are gonna hang, this is gonna hang.

[00:03:58] Your request is gonna hang forever until it times out. So, you have to respond eventually.
>> Speaker 2: Is this like a chain where you are processing the incoming requests and then you can process the response from-
>> Scott Moss: Yeah, that's exactly right. So let me run this, so you can see.

[00:04:21] I'll just put one log here and then we'll start the server. Looks like it already restarted. I'll go over to Insomnia. Which request did I put that on, get? Okay, so for the get one we'll just run it. Go over to the logs you can see it says logging.

[00:04:37] So this one logs first. All right, if I put that array back and add it a few more times. We should see it three times now. Run this and you see I got log in three times. Right so it is changed. It's doing that in sequential order. But it's not parallel.

[00:04:57] It's not running them all at the same time. In sequential order. And it's just gonna keep going. They could also be asynchronous. There's nothing stopping you from doing anything async in here if you want to. It's just, whenever you call next that's when it's gonna go to the next one, or if it errors out, or if you respond, whichever one comes first.

[00:05:11] That's what it's gonna do.
>> Speaker 2: So they won't run in sequence?
>> Scott Moss: No, they run in sequence, but not in parallel. Right, so the won't run at the same time. They'll run sequentially. Yeah.
>> Scott Moss: So even if these were async they still will not run at the same time.

[00:05:28] They would wait to go to the next one. It literally does not move on unless it either called next, there's an error that was not handled or thrown or you respond explicitly. That's the only way it's gonna progress.
>> Speaker 2: So if you threw an error before you called next then your application blows up?

[00:05:47]
>> Scott Moss: Yep, right, in this example yes it will. So let's try it out. So if I throw and error here.
>> Scott Moss: And I do this boom. It [LAUGH] definitely blew up yeah. So it will definitely blow up here. But if I were to pass this error over to next like this, and I'm not handling the error anywhere, then you might still get some unexpected side effects.

[00:06:18] Yeah, I still get the error here. The only difference is instead of the error blowing up here, it blew up inside of express so whenever it's, I do have an error and expressed through it but I didn't handle it somewhere else. When you pass an error to next you're basically telling express, I'm gonna handle this later somewhere else.

[00:06:35] It's like you're gonna have like a catch all error here and went somewhere else, but in this example we don't so it kinda just died anyway. Any other questions?
>> Speaker 2: So there'd be no way to pass the error to your route?
>> Scott Moss: Pass an error, give me an example.

[00:06:55]
>> Speaker 2: Like if your middleware had an error and you wanted your route app.get/data to handle it. I know, I'm just thinking out loud kinda.
>> Scott Moss: Yeah, so, sounds like we're describing it you want the app.get to be able to handle something about the software. So if you did want to do that, so basically how do you communicate between middleware?

[00:07:17] How do you have one middleware communicate to some other middleware, right? So if you're going to pass some data along.
>> Speaker 2: If it's even a good idea, I don't know.
>> Scott Moss: It is a good idea. I would say in that case, as far as like letting a controller handle an error, probably not a good idea, you normally just, and we'll get to it, you normally register an error handler controller at the end of everything that handles all errors and let the controllers just do there job.

[00:07:37] But if you did wanna just pass data along to some other middleware controller, which is a good idea and which we will be doing, then from there normally what you would do is you just attach it to the request object. So I can just say req.mydata = 'hello,' and then I'll call next.

[00:07:53] And then down here below I'll just send that back.
>> Scott Moss: I'm gonna say req.myData. And then now if I run this, you see I get data hello. Pretty simple, but it's really powerful. It's life-changing, really amazing. A super flexible way to write code.