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

@e22m4u/js-trie-router

v0.0.17

Published

HTTP router for Node.js based on a prefix tree

Downloads

595

Readme

@e22m4u/js-trie-router

English | Русский

HTTP router for Node.js based on a prefix tree (trie).

  • Supports path-to-regexp syntax.
  • Parses JSON request body automatically.
  • Parses query string and cookie header.
  • Supports preHandler and postHandler hooks.
  • Supports asynchronous handlers.

Installation

Node.js 16 or higher is required.

npm install @e22m4u/js-trie-router

The module supports ESM and CommonJS standards.

ESM

import {TrieRouter} from '@e22m4u/js-trie-router';

CommonJS

const {TrieRouter} = require('@e22m4u/js-trie-router');

Overview

A basic example of creating a router instance, defining a route and startup Node.js HTTP server.

import http from 'http';
import {TrieRouter} from '@e22m4u/js-trie-router';

const server = new http.Server(); // Node.js HTTP server
const router = new TrieRouter();  // TrieRouter instance

router.defineRoute({              // route definition
  method: 'GET',                  // request method "GET", "POST", etc.
  path: '/',                      // path template, example "/user/:id"
  handler(ctx) {                  // route handler
    return 'Hello world!';
  },
});

server.on('request', router.requestListener); // inject request listener
server.listen(3000, 'localhost');             // listen for requests

// Open in browser http://localhost:3000

Request context

The first parameter of a route handler is an instance of the RequestContext class which has a properties set with contents of a parsed incoming request.

  • container: ServiceContainer instance of service container
  • req: IncomingMessage native incoming request stream
  • res: ServerResponse native server response stream
  • params: ParsedParams key-value object with path parameters
  • query: ParsedQuery key-value object with query string parameters
  • headers: ParsedHeaders key-value object with request headers
  • cookie: ParsedCookie key-value object of parsed cookie header
  • method: string request method in uppercase, e.g. GET, POST, etc.
  • path: string path including query string, e.g. /myPath?foo=bar
  • pathname: string request path, e.g. /myMath
  • body: unknown request body

Example of accessing the context from a route handler.

router.defineRoute({
  method: 'GET',
  path: '/users/:id',
  handler(ctx) {
    // GET /users/10?include=city
    // Cookie: foo=bar; baz=qux;
    console.log(ctx.req);      // IncomingMessage
    console.log(ctx.res);      // ServerResponse
    console.log(ctx.params);   // {id: 10}
    console.log(ctx.query);    // {include: 'city'}
    console.log(ctx.headers);  // {cookie: 'foo=bar; baz=qux;'}
    console.log(ctx.cookie);   // {foo: 'bar', baz: 'qux'}
    console.log(ctx.method);   // "GET"
    console.log(ctx.path);     // "/users/10?include=city"
    console.log(ctx.pathname); // "/users/10"
    // ...
  },
});

Response sending

Return value of a route handler is used as response data. Value type affects representation of a response data. For example, if a response data is of type object, it will be automatically serialized to JSON.

| value | content-type | |-----------|--------------------------| | string | text/plain | | number | application/json | | boolean | application/json | | object | application/json | | Buffer | application/octet-stream | | Stream | application/octet-stream |

Example of sending data as JSON.

router.defineRoute({     // register a route
  // ...
  handler(ctx) {         // incoming request handler
    return {foo: 'bar'}; // response will be encoded to JSON
  },
});

The request context ctx contains a native instance of the ServerResponse class from the http module, which can be used for manual response management.

router.defineRoute({
  // ...
  handler(ctx) {
    res.statusCode = 404;
    res.setHeader('content-type', 'text/plain; charset=utf-8');
    res.end('404 Not Found', 'utf-8');
  },
});

Route hooks

Defining a route with the defineRoute method allows to set up hooks to monitor and intercept requests and responses for a specific route.

  • preHandler executes before a route handler
  • postHandler executes after a route handler

preHandler

Before calling a route handler, operations such as authorization and request validation may be performed in the preHandler hook.

router.defineRoute({ // register a route
  // ...
  preHandler(ctx) {
    // before the route handler
    console.log(`incoming request ${ctx.method} ${ctx.path}`);
    // > incoming request GET /myPath
  },
  handler(ctx) {
    return 'Hello world!';
  },
});

A route handler will not be called if preHandler hook returns a value other than undefined and null, because that value will be sent as response data.

router.defineRoute({ // register a route
  // ...
  preHandler(ctx) {
    // return the response data
    return 'Are you authorized?';
  },
  handler(ctx) {
    // this handler will not be called
    // because the "preHandler" hook
    // has already sent the data
  },
});

postHandler

Return value of a route handler is passed to the second parameter of postHandler hook. It may be useful to modify the value before being sent.

router.defineRoute({
  // ...
  handler(ctx) {
    // return the response data
    return 'Hello world!';
  },
  postHandler(ctx, data) {
    // modify the response data before send
    return data.toUpperCase(); // HELLO WORLD!
  },
});

Global hooks

A TrieRouter instance allows to set up global hooks that have higher priority over route hooks and are called first.

  • preHandler executes before each route handler
  • postHandler executes after each route handler

Global hooks can be added using the addHook method of a router instance, where the first parameter is the hook name and the second is a function.

router.addHook('preHandler', (ctx) => {
  // before a route handler
});

router.addHook('postHandler', (ctx, data) => {
  // after a route handler
});

Similar to route hooks, if a global hook returns a value other than undefined and null, that value will be sent as response data.

Debugging

Set the DEBUG variable to enable log output.

DEBUG=jsTrieRouter* npm run test

Testing

npm run test

License

MIT