API Design in Node.js, v4


Scott Moss

Scott Moss

Superfilter AI
API Design in Node.js, v4

Check out a free preview of the full API Design in Node.js, v4 course

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

Scott introduces the concept of middleware and installs Morgan, a logging middleware for Express. Middleware is a function that can be called for any request or only specific routes. The middleware function calls a next() method when it's complete so the request can finish being processed by the server.


Transcript from the "Middleware" Lesson

>> Last we talked about the routes. We did a little bit with the handlers but didn't really get into it but we got the routes down, we got the sub router. And before we transition into actually interact with the database and doing all that cool stuff. We're gonna learn about middleware.

So, what is middleware? Middleware are basically a list of functions that have the ability to run right before your handlers do, that's basically it. They sit in the middle of your route being called and the actual handler for that route actually executing. They're just different things that you can do before that, if you've ever done something on Redux, you can add all those plugins to Redux.

Those are middleware. It's things you can add to Redux before you serialize it into state or not or whatever, right? It could be a dev tool. It can be a persistent state. It could be a thunk or something like that. Another example of middleware, in front end, will be, that's probably the only example I can think of.

It's mostly a back end thing or network thing. But yeah, it's got some pretty good use cases. So, some use cases are like, maybe you wanna log the request. Yeah, that's perfect job for middleware, you wanna see in your terminal every time someone hit your request. Yeah, that's very helpful for developments.

So you know when a request came in, what the request was, how long it took, maybe you want to handle errors. Which you have to, because remember, one server serves all clients. So if your server crashes, no one can use your app. Whereas on your client, if I was using your app on my browser and it broke, it wouldn't break for everyone else in the world.

It would only break on my computer. But on the server if it broke, it broke for everybody. So you want to handle the errors because it's very important. So middleware can do that. Authentication, you wanna prevent certain people from accessing certain routes unless they're authorized and identified to do so.

Middleware is perfect for that. And pretty much anything else. You can enhance or augment the request object. You can add things to it, transform it. Do whatever you want. And you can just keep doing and you can reuse that stuff. So what does middleware look like? It looks exactly like a handler, where it has a request and a response, but it has this other thing called next.

The next function is exactly what it sounds like. It tells express that, I don't know what I typed there. It tells you express that, we're basically done here in this middleware. We did everything that we wanted to do, so go to the next thing in the stack which can be another middleware function or the handler whatever is next.

Each middleware doesn't know what comes after it cuz you'll see how we can figure it. But this just means, I did what I was supposed to do, I'm done, go to the next thing in the stack, which can be a handler or another middleware. So it's the equivalent of calling res inside of a handler.

Whereas when I say res.json or res.send inside of a handler, I'm done with this work calling next is the middleware saying, I'm done. Middleware can also respond to the request too. Middleware can say read res and stop and never called next. For instance, a use case would be I have a middleware that checks to see if an incoming IP address is from Coca Cola.

And if it is I'm going to, in the request right now and send a message back and say, hey, we're Pepsi, you're Coca Cola get off our website. You can do that inside of a middleware, you can stop doing whatever you want. You can do the same thing a handler can do, you can talk to the databases.

You can literally do whatever you want and then you can also continue on to another middleware that does something else. Or you put everything in one middleware, which I don't recommend. So, all right, I'm making this sound hard than actually is, let's do it. So, let's write some middleware.

First we're gonna use some middleware that we aren't gonna create because it's super useful. And then we're gonna create some middleware. So some really useful middleware that we're gonna use. One of them is called Morgan. So we're gonna npm install Morgan, I am just gonna say save. Morgan is a middleware that logs requests, that's literally all it does, and it's super useful.

So we're gonna install Morgan and then you're gonna go over to server. And then, above all your route declarations you could say, well, first let's import Morgan, I guess, import morgan from morgan, like so. And then after we make an app, we can say app.use. And remember, order matters.

So we always put your middleware at the top, before all your other routes if you want the routes to come after the middleware. So middleware usually comes first, so I'm gonna say app.use morgan and morgan takes in an option of what level of logging do you want. You can do l tiny concise, I like the dev formatting because it gives me everything I need as a developer for logging some of the dev.

And I'm gonna save that. Right, so, app.use doesn't always have to take a mount path like we did down here. You can actually just not put a mount path and it's global for the whole app. This means I'm using this middleware for the entire app. That means every single request that comes into this API has to go through whatever morgan is doing first.

And I can tell you it's doing a console log, that's what it's doing. It's just logging and then it's calling next. So then when it calls next, where does it go? Well, it goes to the next thing in a stack. So in the case of I did an API call to slash next would be here, it would go here.

But what if I did an API call to slash API slash product? Well, next would be slash API slash product and it'll run that handler. So next is always different depending on what the request is. That's why this is middleware doesn't know what next is. It just calls next and express handles the routing of what to call next because again, everything is just basically in an array underneath everything.

Everything's order is kept in track, so it knows what to call next. All right, let's run that and see what I'm talking about. So going to stop my server, start my server. I'm gonna go here and I'm gonna do a get request to my API product. Still got message, hello here, when I go back to the terminal, you see I got this log now.

Morgan did that. It said, so why did a get request to this URL? You sent back a 200 response and it took 1.37 milliseconds. And I don't know if this is how many bytes, how big the payload was? Yeah, that's the size I sent back 19 bytes. So it's very useful, you would use middleware, if you had a product that you bought, I mean, there's so many logging products out there.

I don't even wanna name one. But if you use any logging products, a logger API, they would probably have an SDK that has a middleware that sits on your express that sends your logs to their servers. So, they can show you on a dashboard, data dog or something like that.

Right, like some logging thing. It's probably just a middleware or if you've ever use centri, it's propably a middleware or segments for analytics, probably a middleware because it just look at any single request. Any questions on that? Yes.
>> Do we have any options here like this particular middleware will intercept only these routes?

>> Yeah, that's a great question. So the question was, do we have the options to say only want this middleware to intercept these routes? There's so many ways you can do that. You can do that on the code level where inside you just set the middleware to be global.

And then inside the middleware, you specifically check against a list of routes that you specifically want to do and only run your code there. That's one way. The other way is, you can do it on a configuration level where you only add the middleware to the routes that you want it to affect.

So, for instance we added the middleware globally here but there's nothing stopping me from adding middleware here only for this. Or even further down I can go into the router and only want to add middleware here, for this one, right? So I can specifically add middleware wherever I want, that way, or check myself inside the code.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now