JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 142
  • Score
    100M100P100Q89530F
  • License MIT

HTTP маршрутизатор для Node.js на основе префиксного дерева

Package Exports

  • @e22m4u/js-trie-router

Readme

@e22m4u/js-trie-router

HTTP маршрутизатор для Node.js на основе префиксного дерева (trie).

  • Поддержка path-to-regexp синтаксиса.
  • Автоматический парсинг JSON-тела запроса.
  • Парсинг строки запроса и заголовка Cookie.
  • Поддержка preHandler и postHandler хуков.
  • Позволяет использовать асинхронные обработчики.

Установка

Требуется Node.js 16 и выше.

npm install @e22m4u/js-trie-router

Модуль поддерживает ESM и CommonJS стандарты.

ESM

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

CommonJS

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

Обзор

Базовый пример создания экземпляра роутера, объявления маршрута и передачи слушателя запросов HTTP серверу.

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

const server = new http.Server(); // создание экземпляра HTTP сервера
const router = new TrieRouter();  // создание экземпляра роутера

router.defineRoute({
  method: 'GET',                  // метод запроса "GET", "POST" и т.д.
  path: '/',                      // шаблон пути, пример "/user/:id"
  handler(ctx) {                  // обработчик маршрута
    return 'Hello world!';
  },
});

server.on('request', router.requestListener); // подключение роутера
server.listen(3000, 'localhost');             // прослушивание запросов

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

Контекст запроса

Первый параметр обработчика маршрута принимает экземпляр класса RequestContext с набором свойств, содержащих разобранные данные входящего запроса.

  • container: ServiceContainer экземпляр сервис-контейнера
  • req: IncomingMessage нативный поток входящего запроса
  • res: ServerResponse нативный поток ответа сервера
  • params: ParsedParams объект ключ-значение с параметрами пути
  • query: ParsedQuery объект ключ-значение с параметрами строки запроса
  • headers: ParsedHeaders объект ключ-значение с заголовками запроса
  • cookies: ParsedCookies объект ключ-значение разобранного заголовка Cookie
  • method: string метод запроса в верхнем регистре, например GET, POST и т.д.
  • path: string путь включающий строку запроса, например /myPath?foo=bar
  • pathname: string путь запроса, например /myPath
  • body: unknown тело запроса

Пример доступа к контексту из обработчика маршрута.

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.cookies);  // {foo: 'bar', baz: 'qux'}
    console.log(ctx.method);   // "GET"
    console.log(ctx.path);     // "/users/10?include=city"
    console.log(ctx.pathname); // "/users/10"
    // ...
  },
});

Отправка ответа

Возвращаемое значение обработчика маршрута используется в качестве ответа сервера. Тип значения влияет на представление возвращаемых данных. Например, если результатом будет являться тип object, то такое значение автоматически сериализуется в JSON.

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

Пример возвращаемого значения обработчиком маршрута.

router.defineRoute({     // регистрация маршрута
  // ...
  handler(ctx) {         // обработчик входящего запроса
    return {foo: 'bar'}; // ответ будет представлен в виде JSON
  },
});

Контекст запроса ctx содержит нативный экземпляр класса ServerResponse модуля http, который может быть использован для ручного управления ответом.

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

Хуки маршрута

Определение маршрута методом defineRoute позволяет задать хуки для отслеживания и перехвата входящего запроса и ответа конкретного маршрута.

  • preHandler выполняется перед вызовом обработчика
  • postHandler выполняется после вызова обработчика

preHandler

Перед вызовом обработчика маршрута может потребоваться выполнение таких операции как авторизация и проверка параметров запроса. Для этого можно использовать хук preHandler.

router.defineRoute({ // регистрация маршрута
  // ...
  preHandler(ctx) {
    // перед обработчиком маршрута
    console.log(`Incoming request ${ctx.method} ${ctx.path}`);
    // > incoming request GET /myPath
  },
  handler(ctx) {
    return 'Hello world!';
  },
});

Если хук preHandler возвращает значение отличное от undefined и null, то такое значение будет использовано в качестве ответа сервера, а вызов обработчика маршрута будет пропущен.

router.defineRoute({ // регистрация маршрута
  // ...
  preHandler(ctx) {
    // возвращение ответа сервера
    return 'Are you authorized?';
  },
  handler(ctx) {
    // данный обработчик не будет вызван, так как
    // хук "preHandler" уже отправил ответ
  },
});

postHandler

Возвращаемое значение обработчика маршрута передается вторым аргументом хука postHandler. По аналогии с preHandler, если возвращаемое значение отличается от undefined и null, то такое значение будет использовано в качестве ответа сервера. Это может быть полезно для модификации возвращаемого ответа.

router.defineRoute({
  // ...
  handler(ctx) {
    return 'Hello world!';
  },
  postHandler(ctx, data) {
    // после обработчика маршрута
    return data.toUpperCase(); // HELLO WORLD!
  },
});

Глобальные хуки

Экземпляр роутера TrieRouter позволяет задать глобальные хуки, которые имеют более высокий приоритет перед хуками маршрута, и вызываются в первую очередь.

  • preHandler выполняется перед вызовом обработчика каждого маршрута
  • postHandler выполняется после вызова обработчика каждого маршрута

Добавить глобальные хуки можно методом addHook экземпляра роутера, где первым параметром передается тип хука, а вторым его функция.

router.addHook('preHandler', (ctx) => {
  // перед обработчиком маршрута
});

router.addHook('postHandler', (ctx, data) => {
  // после обработчика маршрута
});

Аналогично хукам маршрута, если глобальный хук возвращает значение отличное от undefined и null, то такое значение будет использовано как ответ сервера.

Отладка

Установка переменной DEBUG включает вывод логов.

DEBUG=jsTrieRouter* npm run test

Тестирование

npm run test

Лицензия

MIT