Middleware

CSCI-UA.0480-008

Middleware

From the Express docs

A middleware is a function with access to the request object (req), the response object (res), and the next middleware in line in the request-response cycle of an Express application.

  • invoked before your final request handler is
  • (between the raw request and the final intended route)
  • called in order that they are added

What's That Mean?

Again, but with more details.

  • middleware is just a function
  • it's a function that has three parameters:
    • a request object (usually req)
    • a response object (usually res)
    • and the next middleware function to be executed (conveniently called next)

Hey. That Sounds Familiar. Isn't That the Same As…

It's All Just Middleware

This should sound pretty familiar to you. It's the same kind of function that we pass to our app.VERB methods.


app.get('/', function(req, res) {
	res.send('Familiar, no?');
});
  • the callback functions that we pass as arguments to these methods behave just like middleware
  • it turns out, Express apps are just a bunch of middleware chained together and called sequentially

"An Express application is essentially a stack of middleware which are executed serially."

Using Middleware

Middleware can be:

  • application - executed for the entire application
  • or router level - only executed for a specific path


You can use middleware simply by calling the aptly named:


// for the whole application:
app.use(yourMiddleWareFunction);

// or... for a specific path:
app.use('path', yourMiddleWareFunction);

So… I'm Using Some Middleware

Can I have multiple middleware?

The fact that there's a next parameter implies… YES!

But what order is the middelware executed in?

  • middleware functions are executed sequentially in the request-response cycle
  • …which means that the order that middleware is included is significant!

Middleware Functions are executed in the order of their inclusion!

Let's Try Creating Your Own Middleware

So, you say you want to make your own middleware, eh? What can you do in your fancy middleware function?

  • you can execute any code you want in your middleware (anything your heart desires!)
  • because they have access to the request and response, they could change those objects before it gets to your routing (!!!)
  • they could also end the whole request-response cycle by sending a response immediately
  • or they could call the next middleware in the stack


Ohhhh. Is there a danger with calling render or send in middleware then?

You can end up skipping other chained middleware.

Calling Next

Furthermore, if the current middleware doesn't end the request-response cycle, it should really remember to call next(). What will happen if it doesn't?

  • a response will never be sent
  • the request will be left hanging
  • (nothing good)

Let's Build Some Hello World Middleware

Create middleware that always logs the word 'hello' for every request.


app.use(function(req, res, next) {
	console.log('hello');
	next();
});

How About Some Useful Middleware, Please!

Create middleware that always logs the request's method and path.


app.use(function(req, res, next) {
	console.log(req.method, req.path);
	next();
});

(also… let's play around with ordering. →)

One Last Custom Middleware

Does anyone remember a response header that identifies the type of server that's being run?


Server:Apache/2.2.22 (Ubuntu)

How about we set our own Server response header?

We can use res.set(headerName, headerValue).


app.use(function(req, res, next) {
	res.set('Server', 'MY AMAZING SUPER COOL SERVER');
	next();
});

About That…

Actually, most people try to suppress or remove that Server header. Why?

Security through obscurity!

  • maybe it's better if you don't reveal anything about your technology or infrastructure
  • (what if there were known exploits for a specific version of the web server that you're running?)

All Together (If You Were Curious)


const express = require('express');
const app = express();

app.use(function(req, res, next) {
	console.log(req.method, req.path);
	next();
});

app.use(function(req, res, next) {
	console.log('hello');
	next();
});

app.use(function(req, res, next) {
	res.set('Server', 'MY AMAZING SUPER COOL SERVER');
	next();
});

app.get('/', function(req, res) {
	res.send('We\'re done here');
});

app.listen(3000);

Pre-Made Middleware

Hey. So… DIY is cool and all, but making our own middleware seems like a lot of work. Are there any pre-built middleware out there? (hint we've used one, and we've seen others)

Some middleware that we've either seen or actually used:

  • static files
  • bodyparser

The Static File Middleware

What do you think the static file middleware does? How does it work in the request-response life cycle?

  • it checks the path in the incoming request
  • tries to find if the file exists in the file system
  • if it doesn't, it calls the next middleware (so if the path is not there, it'll drop through to your routes)
  • more info in the docs

Using the Static File Middleware

How do we actually use the static file middleware?

  • (there's nothing to install, it's bundled with express)
  • you only need to specify your public directory (but you could be courteous about it)

app.use(express.static('public'));

const path = require('path');
const publicPath = path.resolve(__dirname, 'public');
app.use(express.static('public'));

Playing Well With Others

By the way… if we were using our logging middleware from before, how do we make sure that requests handled by the static file middleware are actually logged?

Just make sure that logging is included (app.use) before static files.

Body Parser

The body parser middleware:

  • parses the body (of course) of a request object… why does a request body need parsing?
    • it's probably encoded
    • it's probably compressed
  • body parser gives you access to a compressed and encoded body as JavaScript object
    • we'll mostly use it for urlencoded strings
    • app.use(bodyParser.urlencoded({ extended: false }));
  • more info in the docs

Ahhhh. So Why? What kind of request actually has data in the body?

POST Requests

POST requests send their data in the body. How can we issue a POST request?

  • forms
  • (actually, we can also do it with CURL, Chrome apps/plugins, programmatic clients, like request)


Sooooo… maybe it's time to figure out what this form thing is all about.