Skip to content

Creating middleware

Lloyd Brookes edited this page Jul 6, 2021 · 12 revisions

These docs are for local-web-server v3 and above, see an earlier revision for v2

Local-web-server uses Koa as its middleware engine so I recommend familiarising with the Koa guide to writing middleware.

Create a middleware module

A middleware module should export a class with (at the minimum) a middleware method. This method is passed the active ws configuration and must return a Koa middleware function.

Please see here for the full Middleware class documentation.

This example sets the response body to 'Hello'. Save it to a file named mw-example.js.

class Example {
  middleware (config) {
    return async (ctx, next) => {
      ctx.response.body = 'Hello'
      await next()
    }
  }
}

export default Example

Use the middleware module

Test your module by running the following command. By setting --stack you override the built-in stack with the middleware supplied.

$ ws --stack mw-example.js
Serving at http://mbp.local:8100, http://127.0.0.1:8100, http://192.168.0.100:8100

Check you get the expected response.

$ curl http://127.0.0.1:8100
Hello

Middleware options

You can parameterise middleware by adding an optionDefinitions method which returns one or more OptionDefinition objects. Let's add an optionDefinitions method to our Example class which defines an option called message which will be a string.

class Example {
  optionDefinitions () {
    return [
      { name: 'message', type: String, description: 'A message to print.'}
    ]
  }
  middleware () {
    return (ctx) => {
      ctx.response.body = 'Hello'
    }
  }
}

export default Example

If you view the ws usage guide with the example module loaded you'll see your middleware and its options listed under "Middleware stack" and "Middleware options".

$ ws --stack mw-example.js --help

We can use the --message value to customise our response body.

class Example {
  optionDefinitions () {
    return [
      { name: 'message', type: String, description: 'A message to print.'}
    ]
  }
  middleware (config) {
    return (ctx) => {
      ctx.response.body = config.message
    }
  }
}

export default Example

Now, we can configure our middleware to respond with a different message.

$ ws --stack mw-example.js --message "🦆 🦆 🦆"
Serving at http://mbp.local:8100, http://127.0.0.1:8100, http://192.168.0.100:8100

Check we receive the new, parameterised response.

$ curl http://127.0.0.1:8100
🦆 🦆 🦆

Description

Notice how in the --help output the description field for your middleware is empty. To set a description, define a description method which returns a string.

class Example {
  description () {
    return 'Demonstrating how a response can be controlled by config or command line.'
  }

  optionDefinitions () {
    return [
      { name: 'message', type: String, description: 'A message to print.'}
    ]
  }
  middleware (config) {
    return (ctx) => {
      ctx.response.body = config.message
    }
  }
}

export default Example

Verbose events

To send debug information to the --verbose output, you can emit a verbose event from any method within the module passing a key and value.

class Example {
  middleware () {
    return (ctx) => {
      this.emit('verbose', 'middleware.example.message', 'Responding with Hello')
      ctx.response.body = 'Hello.'
    }
  }
}

export default Example

Chaining middleware

When chaining multiple custom middlewares, be sure each calls next() to trigger the next middleware in the stack.

For example.

class One {
  middleware () {
    return async (ctx, next) => {
      ctx.response.body = 'Hello '
      await next()
    }
  }
}

export default One
class Two {
  middleware () {
    return async (ctx, next) => {
      ctx.response.body += 'there.'
      await next()
    }
  }
}

export default Two

Launch a server with both middleware in the stack.

$ ws --stack one.js two.js
Listening on http://mba4.local:8000, http://127.0.0.1:8000, http://192.168.0.200:8000

$ curl http://127.0.0.1:8000
Hello there.

Share

That's it! Reuse your middleware between projects, publish it on npm and share with the world.

If publishing your middleware as an npm package, be sure to include the lws-middleware keyword so it appears on the official middleware list.

Clone this wiki locally