Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Small HTTP request router for node.js

branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

README.md

jb-router

jb-router is a small HTTP request router for node.js. The aim of this project is to capture some useful features from Express while leaving out as much of the bloat and baggage as possible. There are only two dependences, and the router itself is under 5 kilobytes large.

Example

First, install with npm:

npm install jb-router

and then

var Router = new (require("jb-router"))();

function Log(Request, Response, Callback) { console.log(Request.method + ": " + Request.url); Callback(); }
function Exciting(Request, Response, Callback) { console.log("this is an exciting route"); Callback(); }

function Echo(Request, Response)
{
    Response.Send("Welcome to " + Request.url + "\n", { "ContentType": "text/plain" });
}

function NothingFound(Request, Response)
{
    Response.Send("couldn't find it", { "StatusCode": 404 });
}

Router.Listen({ "Port": 4000 });
Router.Get("/", Echo);
Router.Get("/my-url", Echo);
Router.Get(/^\/some\/regex\/.*/, Exciting, Echo);
Router.Get
(
    "/test/:var1/:var2",
    function(Request, Response) { Response.Send("var1 = " + Request.RegExpResults[0] + ", var2 = " + Request.RegExpResults[1]); }
);

Router.Before(Log);
Router.After(NothingFound);

Some things to note:

  • require("jb-router") returns a Router "class", and we construct a Router object with new.

  • A route can be specified as a regular expression or as a string. The format of route strings is discussed below.

  • See also: example/example.js.

Router class

The Router class is returned by require("jb-router"). A Router object is therefore created by

var RouterClass = require("jb-router");
var Router = new RouterClass();

or, more briefly,

var Router = new (require("jb-router"))();

Multiple routers can be created in one application if the need should arise. There are no options for the Router constructor.

Router::Listen function

Have the router start listening for requests.

Router::Listen(Options)
  • Options: a javascript object with keys
    • Port: required integer, port on which the router should listen
    • Hostname: optional string, hostname on which the router should listen. By default, no hostname is supplied and the router will accept connections addressed to any hostname.

Notes:

  • Router::Listen creates a node.js http.Server.
  • It can be called before or after routes have been added to the router.

Example:

var Router = new (require("jb-router"))();
Router.Listen({ "Port": 8080, "Hostname": "localhost" });

Router::Before function

Install a handler for every request (regardless of route) which is invoked before route-specific handlers are called.

Router::Before(Handler)
  • Handler: an instance of Router::RequestHandler.

Notes:

  • If Router::Before is called multiple times, the handlers will be invoked in the order that Router::Before was called.

Example:

var Router = new (require("jb-router"))();
Router.Before
(
    function(Request, Response, Callback)
    {
        console.log(Request.method + ": " + Request.url);
        Callback();
    }
);

Router::After function

Install a handler for every request which is not finalized by a route-specific handler. In other words, a handler installed with Router::After will operate on every request that slips through the cracks.

Router::After(Handler)
  • Handler: an instance of Router::RequestHandler.

Notes:

  • If Router::After is called multiple times, the handlers will be invoked in the order that Router::After was called.

Example:

var Router = new (require("jb-router"))();
Router.After
(
    function(Request, Response, Callback)
    {
        Response.Send("no route handled " + Request.url, { "StatusCode": 404 });
    }
);

Router::Get/Post/Delete functions

Install a handler for a request with a specific HTTP method (GET/POST/DELETE) on a route.

Router::Get(Match, Handler0, [Handler1, [Handler2, ...]])
Router::Post(Match, Handler0, [Handler1, [Handler2, ...]])
Router::Delete(Match, Handler0, [Handler1, [Handler2, ...]])
  • Match: one of
    • a javascript regular expression object against which to test the requested path.
    • a string which will be interpreted as a regular expression, with the added construct /something/:variable/. This construct (a part of the path prefixed by :) matches any string in between the slashes, and exposes it as part of Request.RegExpResults (albeit not named according to the route). The string is parsed by splitting it on /, replacing any :-prefixed items with ([^\/]+), and then rejoining it as a regular expression.
  • Handler0, etc.: an instance of Router::RequestHandler.

Notes:

  • If there is a querystring on the URL, only the part preceding the ? will be tested against the route regular expression. The querystring is parsed and exposed as a javascript object under Request.Payload.
  • Any number of handlers can be passed, and they will be executed in the order passed.
  • If one handler finalizes the response, subsequent handlers will not be executed.

Example (simple GET):

var Router = new (require("jb-router"))();
Router.Get("/my-url", function(Request, Response) { Response.Send("hello world"); });

Example (GET with query string):

var Router = new (require("jb-router"))();
Router.Get("/query", function(Request, Response) { Response.SendJSON(Request.Payload); });

If we make a GET request /query?a=b&something=500&bhh=f%20g, the output of this example will be

{"a":"b","something":"500","bhh":"f g"}

Example (simple POST):

var Router = new (require("jb-router"))();
Router.Post
(
    "/endpoint",
    function(Request, Response) { Response.SendJSON(Request.Payload); }
);

If we make a POST request to /endpoint with variables abc having value 5 and def having value "hello world", the output of this example will be

{ "abc": 5, "def": "hello world" }

Router::StaticHandler function

A useful request handler for serving static files.

Router::StaticHandler(LocalPath)
  • LocalPath: a string with the path to the directory, on the server, of the files to be served by the route.

Notes:

  • The static files will be served with MIME types according to their extensions.
  • The route should be a regular expression with one match group: the path to the file.

Example:

var Router = new (require("jb-router"))();
Router.Get("/js(/.+)", Router.StaticHandler("./public/javascript"));

The route matches requests for files in the /js directory. If a user requests /js/script.js, the static handler will serve the file ./public/javascript/script.js.

Router::RequestHandler class

A request handler (often also called "middleware") is a function which takes in a request and either responds to it or does some processing on it and then passes it along. An incoming HTTP request gets passed along a chain of such request handlers.

Router::RequestHandler is not really a class. It is simply a

function(Request, Response, Callback)
  • Request: an instance of Router::Request
  • Response: an instance of Router::Response
  • Callback: a function, taking no arguments, indicating that the next request handler should be invoked.

Notes:

  • A Router::RequestHandler should either explicitly invoke Callback or finalize Response in some way (e.g. Response.Send).

Router::Request class

An incoming HTTP request arrives as a bare node.js http.ClientRequest. Router::Request class is simply an augmented version of the http.ClientRequest. Therefore, Router::Request still has all of the original properties of the http.ClientRequest, among them:

  • url: the requested path, including query string.
  • method: the requested HTTP method (e.g. "GET").
  • headers: a javascript object containing the HTTP headers of the request.

The following properties are added to the http.ClientRequest to create a Router::Request object:

  • RegExpResults: an array of values matching the groups specified in the regular expression for the route.
  • Payload: a javascript object containing key/value pairs of data submitted with the request (e.g. query string, form data for a POST request). More specifically: (1) if there is no body to the request, Payload will be an object with key/value pairs from the querystring of the URL, as parsed by querystring.parse. (2) If the body has Content-Type header equal to application/x-www-form-urlencoded, Payload will be an object with key/value pairs from the body, as parsed by querystring.parse. (3) If the body has Content-Type=application/json, Payload will be an object with key/value pairs from the body, as parsed by JSON.parse. If the body is not valid JSON, Payload will be null. (4) If the body has any other Content-Type header, Payload will be the raw string of the body of the request.

Router::Response class

An outgoing HTTP response begins as a bare node.js http.ServerResponse. Router::Response class is simply an augmented version of the http.ServerResponse. Therefore, Router::Response still has all of the original properties and methods of the http.ServerResponse, among them:

  • statusCode: the HTTP status code of the response.
  • finished: a flag indicating that the response has been finalized.
  • writeHead(...): write HTTP headers for the response.
  • write(...): write data to the response stream.

Some convenience methods are added to the http.ServerResponse to create a Router::Response object:

  • Send(Content, Options): Send a payload and finalize the response.

    • Content: string of text to be served.
    • Options: a javascript object with keys:
      • StatusCode: optional integer (default 200).
      • ContentType: optional string (default "text/html").
  • SendJSON(Content): Send a JSON payload with content-type text/json and status code 200 and finalize the response.

    • Content: a javascript object to be served.
  • Redirect(URL): Redirect requests for this route to another URL, which can be remote (http://www.google.com) or not (/new-page).

Something went wrong with that request. Please try again.