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

route-label

v1.2.3

Published

Named router and URL generator, compatible with Express 4 modular routing

Downloads

1,398

Readme

Build Status npm version

What

Register your route as natural as Express' way, PLUS adding name/label to it. Then you can generate URL by calling urlFor.

Example

Either:

// In index.js
router.get('user.detail', '/users/:id', userDetailController);
router.post('user.edit', '/users/:id/edit', userEditController);

router.get('article.list', '/articles', articleListController);
router.get('article.detail', '/articles/:title', articleDetailController);

or:

// In index.js
router.use('user', '/users', userRouter);
router.use('article', '/articles', articleRouter);

// In path/to/module/user/index.js
userRouter.get('detail', '/:id', detailController);
userRouter.post('edit', '/:id/edit', editController);

// In path/to/module/article/index.js
articleRouter.get('list', '/', listController);
articleRouter.get('detail', '/:title', detailController);

You can:

router.urlFor('user.detail', {id: 0})                  -> '/users/0'
router.urlFor('user.edit', {id: 2})                    -> '/users/2/edit'
router.urlFor('article.list')                          -> '/articles'
router.urlFor('article.detail', {title: 'love-craft'}) -> '/articles/love-craft'

Sample Project

See route-label-sample for sample integration on express.js.

Why

Define route in a way you define constants (name => route), because:

  1. No need to remember the route's URL patterns, just the name to generate URL. Useful for large application with many end points.
  2. Easy to change URL patterns, just in the "constant" definition.

Features

  1. Define route as natural as Express' way.
  2. Mount submodule routes using use method, and get the whole route names respect the module - submodule structure by namespaces.
  3. You still can apply middlewares in multiple lines flexibly.
  4. Get the route table and you can decide what to do with it: pass to front end, finding route name based on pattern, etc.

How to use

Installing

npm install --save route-label

Registering Routes

Basic

In the top level express app, wrap the express or express.Router instance with this library:

var app = require('express')();
var router = require('route-label')(app);

Then you can define any routing with this signature:

router.METHOD([name,] path, [middleware ...,] lastMiddleware);

name is optional. If provided, this route will be registered in the route table and you can generate its URL using urlFor.

It may contain alphanumeric, dot, dashes, and underscore.

METHOD is the router's method, such as get, post, put, all, or use.

At the end of your outermost route definitions, call:

router.buildRouteTable();

This will process all registered route above and store it for future URL generation (urlFor). You only need to call it once.

Example:

var router = require('route-label')(app);

router.all('/*', middleware);
router.get('user.detail', '/users/:id', userDetailController);
router.post('user.edit', '/users/:id/edit', userEditController);

router.buildRouteTable();

Mounting Submodule

If you mount another "submodule" with use keyword, the given name will become prefix for all routes inside that submodule. Without giving name, the nested routes inside the submodule won't be registered as named route. Prefixes will be concatenated with dot ('.') character. It is also possible to have subsubmodule and subsubsubmodule.

Example, in your /routes/index.js:

var app = require('express')();
var router = require('route-label')(app);

router.use('article', '/articles', require('/path/to/module/article/index'));

In /path/to/module/article/index.js:

var appRouter = require('express').Router(); // Use express.Router() instead of express()
var router = require('route-label')(appRouter);

router.get('list', '/', listController);
router.post('detail', '/:title', detailController);

module.exports = appRouter; // Return the express.Router() instance

Now you get 'article.list' and 'article.detail' routes defined.

If you provide empty string as names, they will be ignored in the prefix. For example, if you did this:

router.use('', '/articles', articleModule);

We get 'list' and 'detail' routes defined, instead of '.list' and '.detail'

Generate URL

.urlFor

To generate URL, it is not necessary for route-label to wrap app instance.

var router = require('route-label'); // No need to wrap `app` here

Then you can call urlFor with this signature:

urlFor(routeName, [paramObj], [queryObj])

Where paramObj is object containing values to be plugged to the URL, and queryObj is object which will be serialized as query string.

Example:

/*
Consider this route definitions:
  'article.list' => '/articles'
  'article.detail' => '/articles/:title'
*/

// Returns /articles/cool-guy
router.urlFor('article.detail', {title: 'cool-guy'});

// Returns /articles/cool-guy?mode=show
router.urlFor('article.detail', {title: 'cool-guy'}, {mode: 'show'});

// Returns /articles/cool-guy?mode=show&tag=man&tag=people&tag=money
router.urlFor('article.detail', {title: 'cool-guy'}, {mode: 'show', tag: ['man', 'people', 'money']});

// Returns /articles?order=asc
router.urlFor('article.list', {}, {order: 'asc'});

// Throw error, missing `title`
router.urlFor('article.detail', {});
router.urlFor('article.detail', {caption: 'cool-guy'});

.absoluteUrlFor

To generate absolute URL, set the baseUrl with:

router.setBaseUrl(baseUrl);

This works globally, so you only need to set it once. In the main routing file perhaps?

After that you can call absoluteUrlFor anywhere.

Example:

router.setBaseUrl('https://www.cermati.com');

// Returns https://www.cermati.com/articles/cool-guy
router.absoluteUrlFor('article.detail', {title: 'cool-guy'});

.getRouteTable

After buildRouteTable, you can call this anywhere using route-label (with or without wrapping app).

/*
Consider this route definitions:
  'article.list' => '/articles'
  'article.detail' => '/articles/:title'
*/

router.getRouteTable();

Will return:

{
  'article.list': '/articles'
  'article.detail': '/articles/:title'
}

FAQ

Has anyone used this on production server?

Yes, the birthplace of this library, Cermati, and our other projects using Node.js. We have this on production server running since October 2015.

Why bother creating this library?

We reviewed other libraries for named route, but none of them suites our needs, especially for submodule routing. So we decided to build our own solution. Battle tested in production, we proceed to release this as open source.

How does it work internally?

It wraps Express' routing, attaching name in the routes before calling actual Express' routing function. When .buildRouteTable is called, the attached names are traversed in pre-order fashion. The result is stored in table and used for future URL generation.

Can it be used as template helper?

You can, if the template engine allow creation of custom helper. For example in Handlebars.js, you can define custom helper which calls urlFor.

License

MIT