Simple middleware stack for next.js getServerSideProps
(and eventually Api Routes)
import { use, wrap, Middleware } from './use';
interface WithUserVars {
users?: User;
}
const withUser: Middleware<WithUserVars> = async (ctx, vars, next) => {
if (vars.user) {
return next();
}
// Add properties to `vars` to expose to subsequent middleware (avoid mutating ctx)
vars.user = await getUser(ctx.session.userId);
// Continue to next middleware in stack
return next();
}
const role = (role: string): Middleware => use(withUser, (ctx, vars, next) => {
if (!vars.user) {
// Short-circuit
return { redirect: { destination: '/login', permanent: false } };
}
if (!vars.user.roles.includes(role)) {
return { notFound: true };
}
return next();
});
const perf: Middleware = async (ctx, vars, next) => {
const label = `getServerSideProps:${ctx.req.url}:${Date.now()}`;
console.time(label);
const result = await next();
console.timeEnd(label);
return result;
}
const stack = use(perf, role('ADMIN'), withUser, (ctx, vars) => ({
props: { username: vars.user.username }
});
export const getServerSideProps = wrap(stack);
Improvements
any
)FinalMiddleware
which doesn't acceptnext
and can't returnundefined
?use
calls won't be expected to have a final middleware 🤔use(parallel(withUser, withSomeOtherAsyncData), withVersion, () => {});
vars
intonext
so that you're not forced to mutateexpress
fn which interoperates with express-style middlewareuse(express((req, res, next) => { req.foo = true; next(new Error('nope')) }), (ctx) => { props: { foo: ctx.req.foo } })
vars
toctx.vars
so middleware signature is just(ctx, next) => Promise<Result>
/(req, res, next) => Promise<void>
nextjs-use