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

bluegate

v1.1.18

Published

Promise based web framework

Readme

Minimalistic Web Application Framework as Promised

Build Status Coverage Status Dependency Status Known Vulnerabilities

BlueGate is a simple framework to build web applications in NodeJS. It is build on top of the powerful Bluebird library to let you use the ease of Promises to its fullest extent.

Instead of a simple stack with middleware, BlueGate has a sophisticated request flow that fits both REST API's and complex multi-tier applications.

BlueGate can be extended with the following modules:

Installation

Install using npm install bluegate

Quick example

var BlueGate = require('bluegate');

var app = new BlueGate();
app.listen(8080); // Port or unix socket.

app.postvalidation('GET /user/<id:int>', (id) => {
  if (id === 123) {
    throw Error('This is not a valid user id');
  }
});
app.process('GET /user/<id:int>', (id) => {
  // Return page content or promise for content.
  return {id: id};
});

app.process('GET /user/<id:int>/picture', (request, id) => {
  request.mime = 'image/jpeg';
  return new Buffer('...');
);

See the Todo example for a more complete example.

Request flow

Each request follows the steps below:

  • initialize can be used to register request specific handlers
  • authentication should be used to identify the client
  • authorisation should be used for permission checks
  • prevalidation does validation before preprocessing
  • preprocess does the preprocessing (e.g. parsing body)
  • postvalidation does validation after preprocessing
  • process will generate the output
  • postprocess can alter the output (e.g. for templating)
  • send response to client
  • after is for additional work (e.g. statistics)

All remaining steps are skipped when an error occur before sending the response, In that case, we will arrive at the error-flow:

  • error is used to generate the error response for the client
  • send response to client
  • aftererror is for additional work (e.g. statistics)

The name of each step is used as function name to register handlers for it. This can be done on the BlueGate instance (as shown in the example above) or on the this scope within a handler. The first argument is in the form METHOD /path and determines which requests it can handle. This argument can be omitted to enable the handler for all requests.

Writing handlers

Input

Handler functions can accept input via both function arguments and the local scope (this). The local scope is only accessible when using ES5 functions. For ES6 functions you may add the request parameter. The following examples are identical:

// ES5
app.process('GET /list', function() {
  var page = this.getQuery('page', 'int', 1);
});
// ES6
app.process('GET /list', (request) {
  var page = request.getQuery('page', 'int', 1);
});

Input from path parameters is mapped to function arguments. Function arguments that do not have a parameter will get undefined as value.

app.process('GET /user/<name:string>', function(type, name) {
  typeof type === 'undefined';
  typeof name === 'string';
});

Other input is available in the local scope (this.*) or request parameter (request.*). The table below lists all available variables and functions.

Name | Type | Example | Read only? -----------|---------|-----------------------|----------- host | string | www.example.com | yes path | string | /user/john | yes method | string | GET | yes body | * | | yes mime | string | text/html | no status | int | 200 | no query | object | ['page'] | yes headers | object | {'User-Agent': '...'} | yes cookies | object | ['sessionId'] | yes ip | string | 127.0.0.1 | yes date | date | | yes secure | bool | false | yes parameters | object | {...} | yes multipartBoundary | string | | yes

The body type is dependent on the Content-Type header sent by the client.

Content-Type | Type ----------------------|------- application/json | object application/form-data | object text/* | buffer / | Readable stream

The multipartBoundary property is only set when the Content-Type header was set to multipart/*. Parsing multipart data is not done by this framework, since the application may stream the input directly to files or external storage, which is beyond the scope of BlueGate. Popular modules for parsing are busboy, multiparty and dicer. See the upload example for more information on how to handle multipart/form-data requests and file uploads.

Path parameters

Path parameters are passed as function arguments, as shown in the last code example. The following types are available:

Type | Description ---------|-------------------------------------------------------- alpha | Alpha characters (a-z A-Z) alphanum | Alphanumeric characters (a-z A-Z 0-9) bool | Boolean (matches "1", "0", "true" and "false") float | Floats (e.g. -34.3, .3 or 63) int | Positive integer (1..n). Does not match 0. path | Matches all characters including forward slashes ("/") signed | Signed integer (e.g. -123, 0 or 123) string | Matches all characters except forward slashes ("/") unsigned | Unsigned integer (0..n) uuid | Matches UUID versions 1 to 5

Accepting path parameters via function arguments should be preferred above using this.parameters. The last object was added to allow abstract functions to handle multiple callbacks.

It is possible to set new parameters or override existing using setParameter inside a handler. This is illustrated in the following example:

app.initialize('GET /path/<foo:string>', function(foo) {
  this.setParameter('foo', 'bar');
});
app.process('GET /path/<foo:string>', function(foo) {
  // foo == "bar", independent from the actual path argument.
});

The setParameter function requires two arguments; name and value. The value is not casted to the type defined in the path.

Query arguments

Values from the path query ("/news?page=34") can be retreived using this.getQuery. The first argument is the name and the second is the value type. A default value can be provided as thirth argument (defaults to null). The default value is returned when the variable is missing or its value does not match the requested type.

app.process('GET /news', function() {
  var page = this.getQuery('page', 'int', 1);
});

An array of all available query variables is available in this.query. This contains a list of names only, to enforce validation when getting the value.

Output

Output is provided as return value. This can be provided as strings, buffer, readable stream or any JSON serializable value. The MIME-type defaults to "text/html" when using strings, "application/octet-stream" for buffers and stream and "application/json" for other types. JSON output is automatically encoded.

Use this.mime to set a different MIME-type.

app.process('GET /image', function() {
  this.mime = 'image/jpeg';
  return fs.createReadStream('image.jpg');
});

Cookies

Read cookies using getCookie. This is similar to getQuery. The names of all provided cookies can be found in this.cookies.

app.authentication(function() {
  var sessionId = this.getCookie('sessionId', 'alphanum');
});

Use the setCookie function to set a cookie. Arguments are:

  • Name May not contain whitespace, comma, semicolon, equals sign or non-printable characters.
  • Value May not contain whitespace, comma, semicolon or non-printable characters.
  • Expires Given as JavaScript Date-object. Optional, defaults to not expiration date (session cookie).
  • Path E.g. "/forum". Optional.
  • Domain E.g. ".example.com". Optional.
  • HttpOnly Set HttpOnly flag. Given as boolean. Optional, defaults to true.
  • Secure Set Secure flag. Given as boolean. Optional, defaults to true when visited over SSL.

Example:

app.preprocess('POST /login', function() {
  var sessionId = '...';
  var date = new Date();
  date.setDate(date.getDate() + 14);

  // Set a session cookie.
  this.setCookie('sessionId', sessionId);

  // Expires after 2 weeks.
  this.setCookie('sessionId', sessionId, date);

  // Only on /forum.
  this.setCookie('sessionId', sessionId, null, '/forum');

  // Set for example.com and all subdomains.
  this.setCookie('sessionId', sessionId, null, null, '.example.com');
});

HTTP headers

HTTP headers can be set using the setHeader function.

app.preprocess('GET /path', function() {
  this.setHeader('X-Generator', 'CMS');
});

An optional thirth argument can be provided to append headers instead of replacing them.

app.preprocess('GET /path', function() {
  this.setHeader('Cache-Control', 'no-cache', true);
  this.setHeader('Cache-Control', 'no-store', true);
});

HTTP status code

The HTTP status code is 200 by default. This code is changed automatically when an error occurs. The HTTP status for errors is dependent on the phase in which the error occurred.

Phase | Code | Message -------------------|------|------------------------ initialize | 500 | Internal server error authentication | 401 | Authentication required authorisation | 403 | Permission denied prevalidation | 400 | Bad request preprocess | 500 | Internal server error postvalidation | 400 | Bad request process | 500 | Internal server error postprocess | 500 | Internal server error

Additionally, a 404 response ("Not found") is provided when no process handler was found. All phases before process are still executed, because it is possible that those will register a process handler.

It is possible to override the status code from within a handler using this.status.

app.process('POST /object', function() {
  this.status = 201;
  return {messages: ['Created']);
});

Logging

BlueGate will log requests to console by default. You can change this behaviour in the constructor options.

var server = new BlueGate({
  log: false, // or:
  log: function(message) { ... }
});

The format of the log messages is:

2015-05-26T21:15:05 127.0.0.1 "GET /host-test" 200 16 143
 \- Start of request  |           |            |  |   |
                      \ Client IP |            |  |   |
                                  \ Request    |  |   |
                                 Response code /  |   |
                           Response size (bytes)  /   |
                                  Response time (ms)  /

No settings are available to change this format. You can disable logging and register an after / aftererror handler for custom logging.

Security

Running behind a proxy server

When you are running behind a proxy server, you should set the trustedProxies option. This contains a list of IP-addresses used by your proxy servers. The default value for this list is 127.0.0.1. All proxies must add the IP-address to the X-Forwarded-For header. The this.ip variable used in handlers will contain the client IP, even when the client tries to spoof the IP-address by sending a false X-Forwarded-For header.

var app = new BlueGate({
  trustedProxies: ['192.168.1.10', '192.168.1.11']
});

Running behind SSL

The this.secure variable in handles indicates if the client is using HTTPS for this request. This flag relies on the X-Forwarded-Proto header, which should be set by reverse proxies (which may require extra configuration). This value can be spoofed by the client.

Cookies are set with the Secure flag by default when running behind SSL. It's possible to remove it by setting the 7th argument of setCookie to false.

Clickjacking

All HTML responses will include the HTTP-header X-Frame-Options: deny to prevent clickjacking attacks. It is set to the most strict setting by default. You can change its setting in the constructor when you use iframes. Strings are used as header value. Use false to completely remove this header.

var app = new BlueGate({
  clickjacking: 'sameorigin'
});

MIME-sniffing

All responses will include the header X-Content-Type-Options: nosniff by default. This helps to prevent MIME-sniffing attacks. You should leave this header in and make sure that the MIME-type is set correctly. However, you can disable this feature in the constructor.

var app = new BlueGate({
  noMimeSniffing: false
});

Maximum input size

A maxInputSize option is available. This limits the number of bytes accepted in the request body. The default value is 1048576 (1MB). You should lower this value if large requests aren't used to avoid DoS attacks.

var app = new BlueGate({
  maxInputSize: 1024 * 64 // 64 KB
});

The maximum input size does not apply to posted streams (e.g. multipart data). A process function can stop the upload by sending a response, ignoring the stream.