Functional Design Patterns for Express.js by Jonathan Lee Martin

Functional Design Patterns for Express.js by Jonathan Lee Martin

Author:Jonathan Lee Martin
Language: eng
Format: epub
Published: 2019-06-11T16:23:28+00:00


Route Middleware

Sadly not all is well. Try sending a GET /emails request with Insomnia. The request seems to be hanging again because an exception is blowing everything up:

GET /emails (node:44439) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) at jsonBodyParser (lib/json-body-parser.js:5:19) [···]

What’s going on? Well, not every route expects a request body, much less a JSON-formatted body. But jsonBodyParser() runs before every single route as though a JSON-formatted request body is guaranteed. GET requests don’t have a body, so JSON.parse() is trying to parse an empty string.

There are a few approaches to fix this bug. The typical solution is to make jsonBodyParser() a bit more robust to edge cases with some if...else statements. However, apart from making our code uglier, it only postpones other bugs that will emerge because it won’t solve the underlying design problem: only two routes in our backend expect JSON-formatted request bodies!

Inserting middleware with app.use() is a bit like using global variables: tempting and easy, but deadly to reusable software. With few exceptions, “global middleware” is a bad design choice because it is more difficult to “opt-out” of middleware in a few routes than it is to “opt-in” where it’s needed.

Figure 5.3: Route middleware is like a personalized stack for just this route. Instead of adding global middleware with app.use(), we can specify middleware for individual routes with .get() and its siblings. Let’s try it in routes/emails.js:

routes/emails.js const express = require('express'); + const jsonBodyParser = require('../lib/json-body-parser'); const generateId = require('../lib/generate-id'); const emails = require('../fixtures/emails'); [···] emailsRouter.route('/') .get(getEmailsRoute) - .post(createEmailRoute) + .post(jsonBodyParser, createEmailRoute) ; emailsRouter.route('/:id') .get(getEmailRoute) - .patch(updateEmailRoute) + .patch(jsonBodyParser, updateEmailRoute) .delete(deleteEmailRoute) ; [···]

You can add as many middleware functions for a route as you want. They will execute from left to right, so make sure your route function comes last. To get our code working again, let’s nuke jsonBodyParser() from the global middleware stack in index.js:

index.js const express = require('express'); const logger = require('./lib/logger'); - const jsonBodyParser = require('./lib/json-body-parser'); [···] app.use(logger); - app.use(jsonBodyParser); app.use('/users', usersRouter); app.use('/emails', emailsRouter); [···]

Try a few requests again in Insomnia, like POST /emails, PATCH /emails/1 and GET /emails. They should all be working as before!



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.