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

js-routes-loader

v0.6.1

Published

A webpack loader for parsing route definitions in json files and wrapping them with a simple javascript api.

Downloads

8

Readme

npm deps test coverage

js-routes-loader

A webpack loader for parsing route definitions in json files and wrapping them with a simple javascript api.

Install

npm i -D js-routes-loader

Usage

Suppose we have the following routes file:

routes/starships.json

{
  "routes": [
    {
      "name": "starships",
      "path": "/posts"
    },
    {
      "name": "starship",
      "path": "/starships/:id",
      "required_params": ["id"]
    }
  ]
}

Configure the loader in webpack to apply to all your routes files webpack.config.js

module.exports = {
  module: {
    loaders: [
      {
        test: /routes/.*\.json$/,
        loader: 'js-routes-loader',
      },
    ],
  },
};

index.js

const routes = require('./routes/starships.json');

routes.starships();             // '/starships'
routes.starships('enterprise'); // '/starships/enterprise'

Details

Routes JSON Format

The routes json file defines the set of routes available in your app. Suppose we had an web app with a REST api for managing starships and their crew. Its routes file might look like this:

startships.json

{
  "routes": [
    {
      "name": "starships",
      "path": "/starships(.:format)",
      "required_params": [],
      "optional_params": ["format"],
      "methods": ['GET', 'POST']
    },
    {
      "name": "starship",
      "path": "/starships/:id(.:format)",
      "required_params": ["id"],
      "optional_params": ["format"],
      "methods": ["GET", "PUT", "PATCH", "DELETE"]
    },
    {
      "name": "starshipCrewMembers",
      "path": "/starships/:starship_id/crew_members(.:format)",
      "required_params": ["starship_id"],
      "optional_params": ["format"],
      "methods": ["GET", "POST"]
    },
    {
      "name": "starshipCrewMember",
      "path": "/starships/:starship_id/crew_members/:id(.:format)",
      "required_params": ["starship_id", "id"],
      "optional_params": ["format"],
      "methods": ["GET", "PUT", "PATCH", "DELETE"]
    },
    // more routes
  ]
}

Each route objects has the following for properties:

|Property|Type |Description|Required| |--------|:---:|-----------|:------:| |name|String| The name of the route. Must be a valid javascript function name and unique. | Yes | |path|String| The 'spec' of the routes path. Required parameters should be encoded as :param. | Yes | |required_params |Array| A list of required parameters that appear in path. | No | |optional_params |Array| A list of optional parameters that appear in path. | No | |methods |Array| A list of http methods that the route supports. | No |

In production the routes json file will typically be created by exporting the routes from your backend application.

Routes Javascript API

The js-routes-loader converts each route specified in the json file into a javascript function that returns a wrapper around fetch object.

Importing the startships.json file above results is equivalent to four functions with the following signature:

const routes = {
  starships: (options = {}) => fatchWrapper(....),
  starship: (id, options = {}) => fatchWrapper(....),
  starshipCrewMembers: (starthip_id, options = {}) => fatchWrapper(....),
  starshipCrewMember: (starthip_id, id, options = {}) => fatchWrapper(....),
};

path

Returns the path resulting from replacing the required parameters in the path with supplied parameters.

Example: The path to the list of all starships

routes.starships().path; // '/starships'

or the path to the crew member with id=12 on the starship enterprise would be:

routes.starshipCrewMember('enterprise', 12).path; // '/starships/enterprise/crewMembers/12'

options

Each route method takes an optional map of options than affect the path the route generates.

options[optional_params]

Parameters who's keys match entries in the route's optional_params array will be appended replaced in the path.

Example: The path to the crew member with id=12 on the starship enterprise in json format would be:

routes.starshipCrewMember('enterprise', 12, { format: 'json' }).path; // '/starships/enterprise/crewMembers/12.json'

options[queryParams]

Any query string parameters can be passed to the route and will be appended to the path.

Example: The path to search for 'federation' starships in the 'constitution' class would be:

routes.starships({ affiliation: 'federation', class: 'constitution'}).path; // '/starships?affiliation=federation&class=constitution'

options[anchor]

The anchor option is special will be appended to the path as an anchor tag after the query string parameters.

Example: the path to all 'klingon' starhips with the anchor 'bird of prey' would be:

routes.starships({ affiliation: 'klingon', anchor: 'bird of prey'}).path; // '/starships?affiliation=kligon#bird%20of%20prey'

methods

Returns the methods supported by the route:

routes.starships().methods;             // ['GET', 'POST']
routes.starships('enterprise').methods; // ['GET', 'PUT', 'PATCH', 'DELETE']

If the methods array is missing or empty it is assumed that all methods are supported. What's the use of a route that supports no ways of calling it? :confused:.

fetch wrappers

Having easy access to the applications paths is great but given a path you probably want to make some sort of request against that path. Be default js-route-loader ships with a simple wrapper around the Fetch API. The wrapper does two things. First it checks the route supports the http method you are trying to fetch. Second it curries the path for the route into the call to fetch.

Example:

routes.starshipCrewMember('enterprise').fetch({method: 'POST', body: JSON.stringify({ name: 'James T. Kirk', rank: 'Captain' }));
// Equivalent to
fetch('/starships/enterprise/crewMembers', {method: 'POST', body: JSON.stringify({ name: 'James T. Kirk', rank: 'Captain' }) });

You might combine these fetch methods like this:

const readyAwayParty = async () => {
  const response = await routes.starshipCrewMembers('enterprise', { rank: 'ensign', shirt: 'red' }).fetch({method: 'GET'});
  const ensigns = await response.json();
  const firstEnsign = ensigns[0];
  await routes.starshipCrewMember('enterprise', firstEnsign.id).patch( {status: 'away', phasers: 'stun'}).fetch({method: 'GET'});
  return firstEnsign;
};


exploreStrangeNewWorld(readyAwayParty())
  .then((discoveredLifeForms) => {
    console.log(`New life forms discovered ${discoveredLifeForms}`);
  })
  .catch((lostCrew) => {
    console.log("He's dead Jim");
    lostCrew.forEach((crew) => routes.starshipCrewMember('enterprise', crew.id).fetch({method: 'DELETE'}));
  });

More information on using the fetch API can be found in the Using Fetch documentation.

If you are using JS Routes Loader in browsers without fetch support make sure to include the Fetch polyfil in you webpack.

Adding your own fetch Wrapper

By default js-routes-loader uses a thin wrapper around fetch. However, you might want to supply your own featch wrapper to adjust the behavior. For example, suppose all your requests are going to be json and you want to set json headers and always parse the response as json. You would define a fetch wrapper like this by extending the FetchWrapper class:

JsonFetchWrapper.js

import { FetchWrapper } from 'js-routes-loader';

const jsonOptions = {
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
};

class JsonFetchWrapper extends FetchWrapper {
  fetch(options) {
    this.checkMethod(options.method);
    return fetch(this.path, Object.assign(jsonOptions, options))
      .then((response) => response.json());
  }
}

export default (path, methods) => new JsonFetchWrapper(path, methods);

Now either configure js-routes-loader to use your fetch handler for all files:

webpack.config.js

module.exports = {
  module: {
    loaders: [
      {
        test: /routes/.*\.json$/,
        use: [{
          loader: 'js-routes-loader',
          options: {
            fetch: require.resolve('./JsonFetchWrapper'),
          },
        }],
      },
    ],
  },
};

or configure the fetch hanlder via a query parameter in the require statement:

const routes = require('!!js-routes-loader?fetch=./JsonFetchWrapper!./routes/starships.json');