Stop reinventing server middlewares and take advantage of Express ecosystem
Soichi Takamura
Posted on March 21, 2020
TL;DR
flow-middleware creates a portable server handler from any of Express middlewares. You can run all the adapters of express-session and Passport.js stategies in your Next.js, micro and Node native server today.
import flow from 'flow-middleware';
const handle = flow(
// Pass Express middlewares
cookieParser(),
session({ secret: 'x' }),
flash(),
(_reqProxy, resProxy, next) => {
resProxy.redirect('/');
}
);
// Handles Node native IncomingMessage and ServerResponse
handle(req, res);
Checkout the Next.js example with Passport.js integration.
Why
As people start using a new Node server library other than Express, they encounter a lack of middlewares that Express already has, which has been well tested and production-ready many years ago. Some of them try to shape a brand new ecosystem on the new island and some just sail back to Express.
Let's start from admitting Express is one of the most successful, beautifully designed and battle-tested software in the Node-based software. Don't forget its hundreds of outstanding middlewares have been born upon it.
Then why you can't use them? The answers will be summarized into these two:
- It just can't run since they depend on Express's
req.param()
andres.redirect()
. I don't want to hack to make them work in my ${Your favorite server name comes here}. - Pollution. Express officially recommends middlewares to extend object properties such as
req.session = {}
andreq.flash = fn
, where my ${Your favorite server} leaves them clean. Plus, dynamic extensions don't fit today of the TypeScript era.
Yeah, yeah. Then how to solve them both?
How
JavaScript Proxy
.
Wrapping req
and res
by Proxy
that splits Node native and Express properties to be accessed. Express exports clean prototypes we can intercept middleware's calls with. It also lets middlewares to call native methods like res.writeHead()
and res.end()
so native objects properly embed HTTP info like headers and send the response back.
The handler, in the end, returns the proxy objects with like req.session
and req.user
so you can still use them after the middlewares go through.
Getting started
Install it with Express.
yarn add flow-middleware express
flow(...middlewares)
A function flow
creates an http handler from some Express middlewares, processed from left to right of arguments.
import flow from 'flow-middleware';
import { ok } from "assert";
import { createServer } from 'http';
import cookieParser from 'cookie-parser';
import session from 'express-session';
import flash from 'express-flash';
// Creates an async function that handles req and res.
const handle = flow(
cookieParser(),
session({ secret: 'x' }),
flash(),
(reqProxy, _resProxy, next) => {
// Our wrapped objects provide accessors
// that Express middlewares extended💪
ok(reqProxy.cookies);
ok(reqProxy.session);
ok(reqProxy.flash);
next();
}
);
createServer(async (req, res) => {
// Let's run the Express middlewares🚀
const [ reqProxy, resProxy ] = await handle(req, res);
// Native objects are clean thanks to our proxy✨
ok(req.cookies === undefined);
ok(req.session === undefined);
ok(req.flash === undefined);
// You still can access to Express properties here🚚
ok(reqProxy.cookies);
ok(reqProxy.session);
ok(reqProxy.flash);
ok(resProxy.cookie);
ok(resProxy.redirect);
res.end('Hello!');
}).listen(3000);
Check out compose()
function to flexibly share middlewares between multiple endpoints.
Conclusion
It takes years for a new framework to have bug-free middlewares for all the sessions, OAuth and logger adapters. Why don't you take advantage of Express ecosystem, one of the most stable solutions for Node.js?
Posted on March 21, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.