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 🙏

© 2025 – Pkg Stats / Ryan Hefner

backstubber

v0.1.23

Published

Simple yet powerful backend stubs.

Readme

Backstubber

Simple yet powerful backend stubs.

Installation

$ npm install backstubber

Install globally with npm install -g backstubber to use the backstubber CLI binary.

Features

Backstubber lets you easily stub any JSON backend, e.g.:

  • Serve JSON files directly from your file system
  • Generate dynamic data using functions
  • Merge actual service responses with your stubs, adding or modifying attributes

API docs

You can find this README and the latest API docs at bcluca.github.io/backstubber.

Usage

As a library

Create your app with backstubber() and mount your fake endpoints, optionally proxying all unhandled calls to a real service, e.g.:

var backstubber = require('backstubber');

backstubber()
    .mount(__dirname + '/simple')
    .mount(__dirname + '/merge', 'https://api.github.com')
    .mount(__dirname + '/form', 'http://httpbin.org')
    .proxy('*', 'https://api.github.com')
    .listen(3333);

In each endpoint directory, create JSON or JavaScript files named after the HTTP verbs you want your service to respond to, e.g.:

example/
├── app.js
├── form
│   └── post
│       └── post.json
└── simple
    ├── faker
    │   └── get.js
    ├── hello
    │   └── get.json
    └── random
        └── get.js

Example get.json defining a simple static stub:

{
    "foo" : "bar"
}

The following example defines a dynamic stub that is merged on top of a real response from an external service:

{
    "_$$" : false,
    "awesome" : true,
    "followers" : 424242
}

Original response from the external service:

{
    "login": "bcluca",
    "url": "https://api.github.com/users/bcluca",
    "type": "User",
    "name": "Luca Bernardo Ciddio",
    "company": "YellowPages.com",
    "followers": 11
}

Stubbed response:

{
    "login": "bcluca",
    "url": "https://api.github.com/users/bcluca",
    "type": "User",
    "name": "Luca Bernardo Ciddio",
    "company": "YellowPages.com",
    "followers": 424242,
    "awesome": true
}

The followers attribute is modified and a new awesome attribute is added.

You can also stub individual routes inline, e.g.:

var backstubber = require('backstubber');

backstubber()
    .get('/foo/bar', { foo: 'bar' })
    .post('/test', { test: true })
    .all('/baz', { _$$: true, baz: true }, 'https://api.github.com')
    .listen(3333);

As a binary

Usage: backstubber [options]

Options:

  -h, --help                          output usage information
  -V, --version                       output the version number
  -p, --port <port>                   set the port (defaults to 3333)
  -m, --mount <dir>[,<service>]       mount stubs directory, with optional service
  -P, --proxy <endpoint|*>,<service>  proxy unhandled calls (use * to catch all)

Examples:

$ backstubber -m example/simple
$ backstubber -m example/simple -m example/merge,https://api.github.com -p 8080
$ backstubber --mount=example/simple --port=3000
$ backstubber -m example/merge,https://api.github.com -P *,https://api.github.com
Note

If you are using the backstubber binary and your stubs require any packages, make sure you have those installed either locally in any node_modules directory up the tree, or globally.

For instance, if you want to mount the stubs defined in ./example/simple/, please run npm install or npm install -g faker first.

Merging with _$$

If you add a service url to your mount() calls, your stub will proxy all calls to an actual service and merge the responses. In your endpoint file, you can reference the original response with the _$$ attribute.

Setting _$$ to a falsy value (e.g. false or 0) merges your stub data on top of the original response. A truthy value (e.g. true or 1) makes the original attributes "win" over your stub data.

_$$ is falsy by default, meaning that all stubs will overwrite the original response if no _$$ attributes are present.

The rate_limit example illustrates the use of merging overrides:

module.exports = {
    _$$ : 1,              // original attrs merged over the stub
    resources : {
        _$$ : 1,          // same here
        search : {
            _$$ : 0,      // this allows the stub to overwrite foo and limit
            foo : 'bar',
            limit : 42
        },
        core : 42         // this gets replaced by the original core attr
    },
    rate : {
        _$$ : 0,          // limit will be 42 in the final response
        limit : 42
    }
};

_$$ also works with arrays, e.g.:

["_$$", {
    "foo" : "bar"
}]

You can remove attributes from the original response by setting them to undefined, e.g.:

module.exports = {
    _$$ : false,
    documentation_url : undefined           // this attr will be removed
};

Note that this is only allowed in JavaScript stubs. If you are using JSON for your stubs and need this functionality, please use JavaScript instead.

You can also have full control over merging by referencing the original response inside functions, e.g.:

module.exports = {
    _$$ : true,                             // response data takes priority
    message : function (data) {             // custom merging, _$$ ignored
        return 'Original message: ' + data; // uses original attr data
    },
    documentation_url : 'new url'           // _$$ not ignored here
};

Functions can also be used to define merging behavior, e.g.:

module.exports = {
    _$$ : function (data) {
        console.log(data);          // original data also available
        return Math.random() < 0.5; // dynamic merge
    },
    message : 'Updated message'     // randomly merged
};

Request object

In addition to the current data chunk, you can use the original request object req inside callback functions, e.g.:

module.exports = {
    userAgent : function (data, req) {
        return req.headers['user-agent'];
    },
    query : function (data, req) {
        return req.query;
    }
};

Response object

Inside callback functions, you can also access the original response from the external service, e.g.:

module.exports = {
    _$$ : function (data, req, res) {
        res.statusCode = 200;          // Change status code from 404 to 200
        res.headers.status = '200 OK'; // Update status header (github sends that too)
        return true;
    },
    headers : function (data, req, res) {
        console.log(res.body);         // You can access the original response body
        return res.headers;            // Just to show updated headers
    }
};

As shown in the example above, you can also access the original response body and change your fake response status and headers. This works in inline stubs as well, e.g.:

backstubber()
    .get('/headers', function (data, req, res) {
        return {
            headers : res.headers
        };
    }, 'https://api.github.com')
    .listen(3333);

Please note that Backstubber will overwrite the content-type and content-length headers, to make sure that a valid JSON response is sent.

HTTP status codes

When you interact with an external service, you can restrict your stubs to specific HTTP status codes by adding a prefix to their name, e.g.:

example/status/
└── status
    └── :status
        ├── get.200.json
        ├── get.4xx.js
        └── get.json

The x in the status code pattern will match any number.

Stubs with no status specified will be used as a fallback, when no specific status codes are matched. If no generic stubs are found, the request will be proxied to the external service, as usual.

In the example above you can also notice the use of parameters. Naming an endpoint directory with a leading colon, e.g. :status, will make that part of the actual URL available in req.params, e.g. req.params.status.

Example app

Run with:

$ node example/app.js

Test endpoints:

Endpoint | Description --- | --- GET /hello | Simple Hello! message GET /random | Dynamic output using callbacks GET /faker | Example using Faker generators GET / | Simple proxy to the github API POST /post | Simple POST example GET /orgs/github | Merging example using JavaScript GET /users/bcluca | Merging example using JSON GET /rate_limit | Example showing merging overrides GET /users/bcluca/orgs | Array merging example GET /fn | Using response data in callbacks GET /events | Root handler example GET /dynamic | Dynamic merging example GET /req?foo=bar | Example using the request object GET /status/:status | HTTP status code specific stubs GET /res | Example using the response object GET /headers | Inline stub showing response headers