npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

micro-mw

v1.3.0

Published

a simple helper to add middleware to your zeit/micro service

Downloads

15

Readme

Build Status

micro-mw

a simple helper to add middleware to your zeit/micro or Now 2.0 functions.

This is a set of simple helpers to create and apply middleware to your functions using either Zeit's micro framework or Zeit Now 2.0 serverless functions.

The entire runtime is less than 100 lines long and depends only on micro itself.

Install

Install with npm

$ npm i micro-mw

micro-mw requires Node.js v8.0.0 or higher.

Concepts and usage

micro-mw operates in similar fashion to that of other JS frameworks (e.g. Express, Hapi). In this case, when writing request handlers, middleware needs to be applied to the target function via applyMiddleware().

The most typical usage would looke something like:

const { applyMiddleware } = require('micro-mw');

module.exports = applyMiddleware([ middlewareFn1, middlewareFn2 ], (req, res) => {
  // Normal request / response handling logic here
});

Sets

Often, the same middleware needs to be applied to most request handlers within an application or set of serverless functions. For those situations, middleware can be pre-registered as a logical "set" and then applied to each function via applyMiddleware().

Registering a set is as simple as giving it a name and passing in references to the middleware functions that need to be called.

const { createSet } = require('micro-mw');

createSet('my-route-mw', [ middlewareFn1, middlewareFn2 ]);

Then just use the middleware like this:

const { applyMiddleware } = require('micro-mw');

module.exports = applyMiddleware('my-route-mw', (req, res) => {
  // Normal request / response handling logic here
});

Default set / middleware

If you want to apply a set of middleware to all routes automatically (unless otherwise specified), you can define a set of default middleware by using the special keyword default:

const { createSet } = require('micro-mw');

createSet('default', [ middlewareFn1, middlewareFn2 ]);

Then, when creating a route handler, don't specify any middleware at all:

const { applyMiddleware } = require('micro-mw');

module.exports = applyMiddleware((req, res) => {
  // Normal request / response handling logic here
});

Set references

Often, the default middleware is enough for most functions, but occasionally, there is a need to include other middleware in the request flow. For example, you might want to include the default authorization middleware on all requests, but only need database init logic in certain places.

In this case, micro-mw allows references to pre-defined middleware sets anywhere that a middleware function could be specified.

Here are a couple of different ways this feature could be used:

  • Reference one set from another

    const { createSet } = require('micro-mw');
      
    createSet('auth', [ authUserMw, getProfileMw, checkScopesMw ]);
    createSet('db', [ initDbMw ]);
      
    createSet('default', [ 'auth', 'db' ]);
  • Chain sets together

    const { applyMiddleware } = require('micro-mw');
      
    module.exports = applyMiddleware([ 'db', 'auth', myCustomMwFn ], (req, res) => {
      // Normal route logic
    });

Whenever micro-mw encounters a string where a middleware function was expected, it will automatically assume that it is a set reference. Order is important here, as the referenced set will replace the string pointer in that exact location within the array.

If a referenced set doesn't exist, a runtime error will occur and will be processed by the default error handler.

Error handling

By default, micro-mw will catch all sync and async errors that occur within a middleware or route handler and return a response to the client.

To override this, simply create a set called errorHandler and pass in one or more middleware functions that will be triggered in the case that an error is thrown. Be sure to read creating error middleware prior to writing your custom error handlers.

If not overridden, the default error handler will look for the following properties on the error object:

  • err.statusCode: The numeric HTTP status code to send to the client. (default: 500)
  • err.body: The content to set as the response body. This could be a string, object, etc. If a body isn't provided, the value of err.message will be used instead.
  • err.headers: An optional JS object containing keys and values that should be added as HTTP headers in the response.

Additionally, the error handler will output the status code, request method and path, and the error stack trace to the logs via a call to console.error.

You can turn this off or provide your own logging function if desired. Simply override the internal error handler like this:

const { createSet, errorHandler } = require('micro-mw');

createSet('errorHandler', [ errorHandler({ logErrors: true, logger: myLoggerObj }) ]);

Note: Any custom logging object must provide an error function, as the handler will call it like: logger.error(msg).

Writing middleware

Writing middleware that is consumable by micro-mw is really no different than writing a normal request handler. micro-mw uses async/await in order to handle synchronous and asyncrhonous middleware in the same manner.

A typical middleware function looks like this:

async function myMiddleware(req, res) {
  // Do some action based on the request
  let someObj = async requestPromise(url, { json: true });
  req.someObj = someObj;
}

Then use it per the patterns mentioned above. For example:

const { applyMiddleware } = require('micro-mw');

module.exports = applyMiddleware([ myMiddleware ], (req, res) {
  // Typical request handling
});

That's it!

You can, of course, do much more complicated things than this.

Creating error handling middleware

Error handling middleware is almost exactly like "normal" middleware, but make note of a few key differences:

  • The thrown error will be passed into the middleware function as a third param, i.e. (req, res, err) => { ... }

  • The error handler is responsible for sending a response to the client.

  • Error handlers should typically avoid throwing errors themselves, as that will likely result in no response being sent to the client.

Halting request execution

There may be occasions during the lifecycle of a request, where middleware needs to send a response early. An example of this scenario might be when using CORS and responding to an OPTIONS request from a browser. In this case, the CORS middleware may send a response prior to all of the middleware or even the request handler being run.

If the remaining middleware and handlers run, an exception may be thrown when an attempt to send another response occurs.

The stopRequest function is provided for a middleware function to signal that a response has been sent and that any remaining steps in the request should be canceled.

Consider the following sample:

const { applyMiddleware, stopRequest } = require('micro-mw');

function middlewareFn1(req, res) {
  // Send a response early
  ...
  stopRequest(req);
}

module.exports = applyMiddleware([ middlewareFn1, middlewareFn2 ], (req, res) => {
  // Normal request / response handling logic here
});

In this scenario, middlewareFn1 will run, but by calling stopRequest(req), the remaining handlers (i.e. middlewareFn2 and the normal request/response handler) will not be called.

Contributing

Pull requests and stars are always welcome. For bugs and feature requests, please create an issue

Author

Matt Hamann

Thanks also to Mathias Karstädt for some inspiration in his work on micro-middleware.