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

node-laravel-router

v2.0.1

Published

A Laravel-inspired router for node.js apps

Downloads

12

Readme

node-laravel-router

A Laravel-inspired router for node.js apps.

(Forked from Express Laravel Router)

NPM version Node version NPM Downloads License Conventional commits Tests Coverage

Motivation

This router is an alternative to routers such as the one that ships with express.js. Instead of manually creating instances of express.Router, for example, you can define your routes in group closures, where it becomes easier to create and reason about the shared properties of your routes.

Also, this router allows you to execute custom code for each route definition, which can be useful for many things, e.g. injecting dependencies into each request handler, or automatically creating a swagger/openapi spec from your routes.

There are also some extra features like being able to name and generate urls strings for each route.

To summarize:

  • Easily create and organize route groups
  • Execute custom code for each route definition
  • Generate urls for a given route definition

Installation

npm install node-laravel-router --save

Quickstart

The examples below will create two routes:

  1. A GET to /api/v1/users/{userId}
  2. A POST to /api/v1/auth

Express app example

const express = require('express');
const createRouter = require('node-laravel-router').createRouter;

const app = express();
const router = createRouter(app);

router.group('/api', (router) => {
    router.group('/v1', (router) => {
        router.group('/users', (router) => {
            router.get('/{userId}', (req, res) => { /* request handler logic */ });    
        });

        router.post('/auth', (req, res) => { /* request handler logic */ });
    });
});

To create the above example in pure express.js, it would look something like the following:

const express = require('express');

const app = express();
const apiRouter = express.Router();
const v1Router = express.Router();
const usersRouter = express.Router();

usersRouter.get('/:userId', (req, res) => { /* request handler logic */ });

v1Router.use('/users', usersRouter);
v1Router.get('/auth', (req, res) => { /* request handler logic */ });

apiRouter.use('/v1', v1Router);

app.use('/api', apiRouter);

The pure express.js version is not only visually harder to reason about, but it becomes increasingly more complex as more routes and middleware are added.

Generic Node app example

const createRouter = require('node-laravel-router').createRouter;
const router = createRouter();

router.group('/api', (router) => {
    router.group('/v1', (router) => {
        router.group('/users', (router) => {
            router.get('/{userId}', (req, res) => { /* request handler logic */ });    
        });

        router.post('/auth', (req, res) => { /* request handler logic */ });
    });
});

// When we pass an Express (or Express-type) app, like in the Express app example above,
// routing is automatically applied once we call the router's methods.
// With our generic, non-Express app, however, routing is not automatically.
// To apply the routing, we have to call the router's apply method as follows.
// Let's assume we are using an Express app:
router.apply((route) => {
  // Do something with route.
  // For example, assuming we have a connect-middleware-supported app
  // stored in an `app` variable:
  const { method, path, handlers } = route;

  app[method](path, handlers);
});

Usage

Our quickstart example used strings as the first argument for both the router.group and router.get methods. You are also able to supply an options object instead, for more powerful functionality. Supplying just a string is actually a shortcut to setting the prefix option in the group options object, and the uri option in the route options object.

Group options

The full group options object with their default values looks like this:

{
    "prefix": "/", // url prefix shared by all routes in this group
    "middleware": [], // middleware shared by all routes in this group
    "namespace": "", // namespace shared by all named routes in this group
    "patterns": {}, // regex patterns shared by all route params in this group
    "meta": {} // additional meta data to associate to all routes in this group
}

Note that all fields are optional, and any combination of fields can be used.

Also note that the following are all equivalent:

router.group({ prefix: '/api' }, (router) => {

});

// shortcut to the above
router.group('/api', (router) => {

});

For more details, see the wiki page.

Route options

The full route options object with their default values looks like this:

{
    "method": "get", // the HTTP method for this route definition
    "uri": "/", // the url fragment for this route definition
    "middleware": [], // the middleware specific to this route definition
    "name": "", // a name to associate to this route definition
    "patterns": {}, // any patterns specific to this route definition
    "meta": {} // any additional meta data to associate to this route definition
}

Note that all fields are optional, and any combination of fields can be used.

Also note that the following are all equivalent:

router.route({ method: 'get', uri: '/api' }, (req, res) => {

});

// the default method is "get"
router.route({ uri: '/api' }, (req, res) => {

});

// the default method is "get", and if a string is used instead of an object, that string becomes the uri option.
router.route('/api', (req, res) => {

});

// using router.{method} prefills the options object with the correct method.
router.get({ uri: '/api' }, (req, res) => {

});

// shortcut to the above
router.get('/api', (req, res) => {

});

For more details, see the wiki page.

Full API

Below are all the methods available on a router.

router.group(options|prefix, closure)

Creates a route group and provides a new router instance inside the closure to perform additional routing inside that group.

router.route(options|uri, action)

Creates a route definition and associates an action with it. The action is then passed to a mapActionToHandler function, whose job it is to return the familiar express.js requestHandler function, whose signature is:

(req, res) => {}

The default mapActionToHandler function assumes that the action passed to router.route is already an express.js requestHandler function. This behavior can be changed by supplying a new mapActionToHandler function to createRouter:

const mapActionToHandler = (action, routeDescription, routeOptions) => {

    return action.customHandler;
};

const router = createRouter(app, mapActionToHandler);

router.route('/users', { customHandler: (req, res) => {} });

The above example now expects that the action is an object with a customHandler property.

router.{method}(options|uri, action)

Instead of supplying a method in the options of router.route, you can simply call router.{method}, which will set the proper method field in the options.

router.route({ method: 'post', uri: '/create' }, (req, res) => {

});

// shortcut to the above
router.post('/create', (req, res) => {

});
router.serve(uri, staticMiddleware)

Creates a route that serves static files.

router.serve('/assets', express.static('./public/assets'));
router.url(name, params={}, options={})

Creates and returns a url for the route definition with the given name. If that route contains params, you can pass in values to fill in the params in the optional params object. Any extra fields found in the params object but not found in the route definition will be considered query params, and will be appended to the url as a query string.

Query strings are generated via the qs module, and so any options that you'd like to pass to qs.stringify can be done via the optional options object.

If there are any patterns on the params, they must be honored by the supplied params, or an error will be thrown.

router.group({ prefix: '/user/{userId}', namespace: 'user.' }, (router) => {

    router.get({ uri: '/friend/{friendId}', name: 'getFriend' }, (req, res) => {

    });
});

const url = router.url('user.getFriend', { userId: 1, friendId: 2, foo: 'bar' });
// url will equal /user/1/friend/2?foo=bar
router.get({
    uri: '/user/{userId}',
    name: 'getUser',
    patterns: {
        userId: /^\d+$/
    }
}, (req, res) => {

});
const url = router.url('getUser', { userId: "one"}); // this will throw an error, because userId is expected to be a number.
router.app

Grants access to the express app object that was passed in to createRouter.

Extras

In addition to the createRouter function, this package also exports laravelToExpress and uriWithParams functions.

laravelToExpress(uri = '', patterns = {})

Accepts a string uri written in the Laravel way (e.g. /user/{userId}) and an optional object of regex patterns, and returns the express.js version (e.g. /user/:userId).

uriWithParams(uri = '', params = {}, patterns = {}, options = {})

Accepts a string uri with optional params (e.g. /user/{userId}). If that uri contains params, you can pass in values to fill in the params in the optional params object. Any extra fields found in the params object but not found in the route definition will be considered query params, and will be appended to the url as a query string.

Query strings are generated via the qs module, and so any options that you'd like to pass to qs.stringify can be done via the optional options object.

If there are any patterns on the params, they must be honored by the supplied params, or an error will be thrown.

paramsFromUri(uri = '')

Accepts a string uri and will return an object that includes and array of required and optional params found in the uri.

const uri = '/users/{userId}/friends/{friendId}/{username?}';
const params = paramsFromUri(uri);
/**
* params looks like:
* { required: ["userId", "friendId"], optional: ["username"] }
*/

Differences to Laravel

Unlike Laravel routes, chaining is discarded in favor of objects containing options. I found this to be a much clearer API.

Additionally, some of Laravel's naming has been updated or repurposed for clarity, e.g. Laravel's "as" has become "name" in route definitions, and "namespace" in route groups.