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

json-router

v0.0.2

Published

An alternative mobile-focused router/rpc middleware that uses the JSON body instead of URL slugs to route requests

Downloads

4

Readme

JSON Router

An alternative mobile-focused router/RPC middleware that uses the JSON body instead of URL slugs to route requests.

The major advantage of this approach is that it easily allows multiple server requests to occur per HTTP request. This reduces latency in your client with network constrained devices like mobile apps.

JSON Router works similar to javascript Function.apply() by taking a name and a variable number of arguments via an array. The request object can handle an array of server requests. The values returned by each request handler and will be aggregated into a JSON array which will be returned to the client.

JSON Router can take an optional callback if you would like to do custom handling on the result object.

Install

npm install --save json-router

Simple Usage

For the simple use case, JSON Router is straightforward. On the server, you pass the router a variable number of handler names and handler functions. You then pass your server (express, connect, restify, etc.) the router middleware after the JSON body parser.


var express = require('express');
var bodyParser = require('body-parser');
var jsonRouter = require('json-router');

var app = express();
app.use(bodyParser.json());

jsonRouter.newRequest("myRequestName1", function(context, arguments, callback) {
  // ...
  return callback(null, retValue);
});

jsonRouter.newRequest("myRequestName2", function(context, arguments, callback) {
  // ...
  return callback(null, [retValue1, retValue2]);
});

app.use(jsonRouter.middleware());

On the client, you send the server a JSON object in the HTTP body using POST. The middleware looks for JSON objects that have the top-level property 'jsonRoute' (this can be changed with the routeProperty option). If this property does not exist, the server will continue on with the middleware chain.


{
  "jsonRoute": {
    "name": "myRequestName1",
    "arguments": [ "foo" ]
  }
}

JSON router will reply with a JSON object containing the result


{
  "requestId": "myRequestName1",
  "result": "myResult"
}

Advanced Usage

Multiple Requests

JSON Router can take multiple requests per HTTP request


{
  "jsonRoute": [
    {
      "name": "myRequestName1",
      "arguments": [ "foo" ]
    },
    {
      "name": "myRequestName2",
      "arguments": [ "arg1", "arg2", "arg3" ]
    }
  ]
}

Or you can use an object-literal notation where each key is the request's requestId.


{
  "jsonRoute": {
    "myRequestName1": {
      "arguments": [ "foo" ]
    },
    "myRequestName2": {
      "arguments": [ "arg1", "arg2", "arg3" ]
    }
  }
}

Similarly, the router will reply with multiple results


{
  "myRequestName1": {
    "requestId": "myRequestName1",
    "result": "myResult"
  },
  "myRequestName2": {
    "requestId": "myRequestName2",
    "result": [ 1, 2, 3 ]
  }
}

If there is an error, the response object will use the error property instead of a non-200 HTTP code. This is because it may be possible that some request handlers succeed while other fail.


{
  "myRequestName1": {
    "requestId": "myRequestName1",
    "error": "My Error String"
  },
  "myRequestName2": {
    "requestId": "myRequestName2",
    "result": [ 1, 2, 3 ]
  }
}

If you would like to execute the same handler function multiple times in a single request, you need to give each request a unique requestId (this defaults to the name if not provided)


{
  "jsonRoute": [
    {
      "name": "myRequestName1",
      "requestId": "passFooToReq1",
      "arguments": [ "foo" ]
    },
    {
      "name": "myRequestName1",
      "requestId": "emptyReq1",
      "arguments": []
    }
  ]
}

Dependencies

Normally, JSON Router will run all requests concurrently. However, this behavior can be modified using dependencies between requests. The property dependsOn causes JSON Router to build a dependency tree to execute the requests. In this example, myRequestName2 will run after myRequestName1 (myRequestName3 will run concurrently with myRequestName1).


{
  "jsonRoute": [
    {
      "name": "myRequestName1",
      "arguments": [ "foo" ]
    },
    {
      "name": "myRequestName2",
      "dependsOn": "myRequestName1",
      "arguments": [ "bar" ]
    },
    {
      "name": "myRequestName3",
      "arguments": [ "baz" ]
    }
  ]
}

If a request handler fails, all dependent children requests will be cancelled and not run.


{
  "myRequestName1": {
    "requestId": "myRequestName1",
    "error": "My Error String"
  },
  "myRequestName2": {
    "requestId": "myRequestName2",
    "error": "Request skipped due to failed dependency"
  },
  "myRequestName3": {
    "requestId": "myRequestName2",
    "result": [ 1, 2, 3 ]
  }
}

API

Handler Function

The handler function should provide the follow signature

handlerFunc = function(context, arguments, callback)

Context

The context object provide help object and functions to use in your handler

| Property | Type | Description | | :---: | :---: | --- | | name | String | Request handler name | | requestId | String | Request handler requestId (by default is equal to name) | | dependsOn | String | The requestId of the request handler that this request depends on (if any) | | parentResult | Object | The result that the parent request returned (if dependsOn exists) | | request | Object | The request object used by JSON Router | | httpReq | Object | HTTP request object passed to the middleware | | httpRes | Object | HTTP response object passed to the middleware (don't use directly in handler function) | | getResult | function | getResult(reqId) Returns the result object of requestId if it has finished running | | getRequest | function | getRequest(reqId) Returns the request object of requestId | | enqueueRequest | function | enqueueRequest(reqName, args, reqId, dependsOn) Dynamically adds a request to be run | | cancelRequest | function | cancelRequest(reqId) Dynamically cancels a request | | getRequestHandler | function | getRequestHandler(name) Returns the request handler function | | newRequest | function | newRequest(name, handler) Adds a new request handler function to JSON Router |

Arguments

Arguments will always be an array type

Callback

The callback to the handler function accepts the following signature

callback = function(err, result)

Middlware Options

JSON Router can take options and a custom callback function when instantiating the middleware function.

app.use(jsonRouter.middleware(opts, callback));

Options

The following options are supported

| Option | Type | Default | Description | | :---: | :---: | :---: | --- | | routeProperty | String | jsonRoute | The top-level property that indicates the incoming JSON object should be handled by the router middleware | | flattenSingle | Boolean | true | If there is only one request handler, the response object will be flattened instead of being keyed by one requestId | | sendObject | Boolean | true | If option is false, the response object will return an array of responses instead of a requestId keyed object |

Callback Function

If you would like to handle the results of the JSON router manually, you can provide a callback function with the following signature:

callback = function(req, res, results, next)

By default, JSON Router uses the following callback function to send a JSON object to the client

function(req, res, results, next) {
  return res.json(results);
}

Events

JSON router emits events that can be subscribed to

| Event | Signature | Description | | :---: | :---: | --- | | status | function(reqId, status, req) | emitted whenever a requests' status changes (waiting, cancelled, running, finished) |

Example


var jsonRouter = require('json-router');
jsonRouter.on('status', function(reqId, status, req) {
  console.log("Request: " + reqId + " changed to " + status);
});

Coming Soon

Object literal notation for dependencies.

License

MIT License