io-middleware

2.0.0 • Public • Published

io-middleware

Creates middleware that will accumulate state.

Example

import express from 'express'
import { ioMiddleware, FINISHED } from 'io-middleware'

express().get(
  '/user/:id',
  ioMiddleware(
    null, // initial value
    async (req, res) => fetchUser(req.params.id),
    async (req, res, user) => ({ name: user.name, email: user.email }),
    (req, res, state) => {
      res.json(state)
      return FINISHED // prevents any further middleware being called
    },
  ),
)

Typing state changes between middleware

One of the problems we face when writing reusable middleware is to make sure that particular state is available before they're used.

For example, lets say I have one piece of middleware that creates a "local":

function articleInfo() {
  return (req, res, next) => {
    res.locals.articleId = getArticleFromReferrer(req)
    if (!res.locals.articleId) next(new ServerError(404))
    else next()
  }
}

Then in another piece of middleware that wants use that "local":

function partitionKey() {
  return (req, res, next) => {
    res.locals.partitionKey = partitionLookUp(res.locals.articleId)
    if (!res.locals.partitionKey) next(new ServerError(404))
    else next()
  }
}

We can then join our middleware together:

express().get('/partition', article(), partitionKey(), (req, res) => {
  // handle response
})

If we were to create another route and forget to assign an articleId to our locals, before using the partitionKey() we'd have problem.

Strongly typing our middleware can help us ensure that the required state has been populated.

import { FINISH, ioMiddleware, IOMiddleware } from 'io-middleware'

function articleInfo<I>(): IOMiddleware<I, I & { articleId: string }> {
  return (req, res, state) => {
    const articleId = getArticleFromReferrer(req)
    if (!articleId) throw new ServerError(404)
    return { ...state, articleId }
  }
}

function partitionKey<I extends { articleId: string }>(): IOMiddleware<
  I,
  I & { partitionKey: string }
> {
  return (req, res, state) => {
    const partitionKey = partitionLookUp(state.articleId)
    if (!partitionKey) throw new ServerError(404)
    return { ...state, partitionKey }
  }
}

express().get(
  '/partition',
  ioMiddleware(
    {},
    articleInfo(), // If this were to be removed our project would not compile
    partitionKey(),
    (req, res, state) => {
      res.json(state)
      return FINISH
    },
  ),
)

Package Sidebar

Install

npm i io-middleware

Weekly Downloads

5

Version

2.0.0

License

MIT

Unpacked Size

91.6 kB

Total Files

19

Last publish

Collaborators

  • johngeorgewright