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

dagwood

v0.0.1

Published

Bi-directional (sandwiching) middleware for Connect-like applications

Downloads

16

Readme

Dagwood

Create bi-directional middleware for more delicious routes.

Build status on Travis-CI

The problem

Connect middleware is great--it feels a lot like coding against Rack or WSGI and makes building node apps fun! But there's a major difference between Ruby or Python and Node--that whole async thing.

Consider an example:

class MyRackMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    do_stuff_before_a_slow_downstream_handler
    @app.call(env)
    do_stuff_after
  end

Even though our downstream call may not return instantly, all is good, our 3 steps run in order.

In node, however:

function MyConnectMiddleware (req, res, next) {
  doStuffBeforeASlowDownstreamHandler();
  next();
  doStuffAfter();
}

We have no guarantee of the order in which things ran, and next affords us no promise to help keep things in sync. It's pretty likely, in fact, that doStuffAfter will run before we get anywhere into the meat of our route.

What's worse, res.send/res.end stop the middleware stack in its tracks and write back to the browser, so you've got to do horrible things to even the most trivially complex controllers to get any code reuse where postprocessing is concerned.

Let Dagwood do those horrible things for you.

Dagwood sandwiches your routes by decorating res.[s]end to call a response handler prior to closing out. This can be stacked to arbitrary depths and follows LIFO on the response side.

Here's an example:

var BidirectionalMiddleware = require('dagwood').middleware;

var myMiddleware = new BidirectionalMiddleware('myMiddleware',
  function processRequest  (req, res, next) { console.log('Hi!'); },
  function processResponse (req, res, next) { console.log('Bye!');});

var app = require('express')();
app.use(myMiddleware);
app.get('/', function (req, res, next) {
    console.log('Nice to see you!');
    res.send(200);
});

If you run this server and hit /, you'll see the following in your console:

Hi!
Nice to see you!
Bye!

Usage

app.use(new middleware(name, requestHandler, responseHandler))

| Param | Required? | Description | |:------|:----------|:------------| |name | yes | A unique name for this middleware. This is required to enable idempotence in function wrapping and calling to keep things sane. Internally, the name will be expanded into a namespace on res.[s]end that will hold some state. | |requestHandler | yes | A middleware function with the signature (req, res, next). This will run at the insertion point and behaves like traditional connect middleware. Behind the scenes it will set up the response handler if provided. | |responseHandler| no | A middleware function with the signature (req, res, next). This will run right before res.send is called, after your route code has executed. The first requestHandler applied is the last responseHandler to run. |

Scary words of warning and certain doom

This is alpha software so take it with all of the appropriate grains of salt. But also there are some specific things to keep in mind:

  1. If your route throws an error, the responseHandler won't run.

    Don't do really important transactional stuff here. If your use case can deal with the server/state being thrown away, this may suit it.

  2. You can't manipulate the response by reference after calling res.send.

    At least not yet. Right now the original arguments to res.send are cached at call-time, so the response text you pass to res.send is what gets written no matter how you change the response's internal state. Headers, on the other hand, are a different story.