Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/e22m4u/js-trie-router
HTTP router for Node.js based on a prefix tree
https://github.com/e22m4u/js-trie-router
esm http javascript nodejs prefix-tree router server trie typescript
Last synced: 7 days ago
JSON representation
HTTP router for Node.js based on a prefix tree
- Host: GitHub
- URL: https://github.com/e22m4u/js-trie-router
- Owner: e22m4u
- License: mit
- Created: 2024-09-04T12:23:43.000Z (3 months ago)
- Default Branch: master
- Last Pushed: 2024-11-09T14:00:38.000Z (10 days ago)
- Last Synced: 2024-11-10T09:17:22.959Z (9 days ago)
- Topics: esm, http, javascript, nodejs, prefix-tree, router, server, trie, typescript
- Language: JavaScript
- Homepage:
- Size: 125 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README-ru.md
- License: LICENSE
Awesome Lists containing this project
README
## @e22m4u/js-trie-router
*[English](./README.md) | Русский*
HTTP роутер для Node.js на основе
[префиксного дерева](https://ru.wikipedia.org/wiki/Trie) (trie).- Поддержка [path-to-regexp](https://github.com/pillarjs/path-to-regexp) синтаксиса.
- Автоматический парсинг JSON-тела запроса.
- Парсинг строки запроса и заголовка `cookie`.
- Поддержка `preHandler` и `postHandler` хуков.
- Позволяет использовать асинхронные обработчики.## Установка
Требуется Node.js 16 и выше.
```bash
npm install @e22m4u/js-trie-router
```Модуль поддерживает ESM и CommonJS стандарты.
*ESM*
```js
import {TrieRouter} from '@e22m4u/js-trie-router';
```*CommonJS*
```js
const {TrieRouter} = require('@e22m4u/js-trie-router');
```## Обзор
Базовый пример создания экземпляра роутера, объявления маршрута
и передачи слушателя запросов HTTP серверу.```js
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` экземпляр [сервис-контейнера](https://npmjs.com/package/@e22m4u/js-service)
- `req: IncomingMessage` нативный поток входящего запроса
- `res: ServerResponse` нативный поток ответа сервера
- `params: ParsedParams` объект ключ-значение с параметрами пути
- `query: ParsedQuery` объект ключ-значение с параметрами строки запроса
- `headers: ParsedHeaders` объект ключ-значение с заголовками запроса
- `cookie: ParsedCookie` объект ключ-значение разобранного заголовка `cookie`
- `method: string` метод запроса в верхнем регистре, например `GET`, `POST` и т.д.
- `path: string` путь включающий строку запроса, например `/myPath?foo=bar`
- `pathname: string` путь запроса, например `/myMath`
- `body: unknown` тело запросаПример доступа к контексту из обработчика маршрута.
```js
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"
// ...
},
});
```### Отправка ответа
Возвращаемое значение обработчика маршрута используется в качестве ответа
сервера. Тип значения влияет на представление возвращаемых данных. Например,
если результатом будет являться тип `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 |Пример возвращаемого значения обработчиком маршрута.
```js
router.defineRoute({ // регистрация маршрута
// ...
handler(ctx) { // обработчик входящего запроса
return {foo: 'bar'}; // ответ будет представлен в виде JSON
},
});
```Контекст запроса `ctx` содержит нативный экземпляр класса `ServerResponse`
модуля `http`, который может быть использован для ручного управления ответом.```js
router.defineRoute({
// ...
handler(ctx) {
res.statusCode = 404;
res.setHeader('content-type', 'text/plain; charset=utf-8');
res.end('404 Not Found', 'utf-8');
},
});
```### Хуки маршрута
Определение маршрута методом `defineRoute` позволяет задать хуки
для отслеживания и перехвата входящего запроса и ответа
конкретного маршрута.- `preHandler` выполняется перед вызовом обработчика
- `postHandler` выполняется после вызова обработчика#### preHandler
Перед вызовом обработчика маршрута может потребоваться выполнение
таких операции как авторизация и проверка параметров запроса. Для
этого можно использовать хук `preHandler`.```js
router.defineRoute({ // регистрация маршрута
// ...
preHandler(ctx) {
// перед обработчиком маршрута
console.log(`Incoming request ${ctx.method} ${ctx.path}`);
// > incoming request GET /myPath
},
handler(ctx) {
return 'Hello world!';
},
});
```Если хук `preHandler` возвращает значение отличное от `undefined` и `null`,
то такое значение будет использовано в качестве ответа сервера, а вызов
обработчика маршрута будет пропущен.```js
router.defineRoute({ // регистрация маршрута
// ...
preHandler(ctx) {
// возвращение ответа сервера
return 'Are you authorized?';
},
handler(ctx) {
// данный обработчик не будет вызван, так как
// хук "preHandler" уже отправил ответ
},
});
```#### postHandler
Возвращаемое значение обработчика маршрута передается вторым аргументом
хука `postHandler`. По аналогии с `preHandler`, если возвращаемое
значение отличается от `undefined` и `null`, то такое значение будет
использовано в качестве ответа сервера. Это может быть полезно для
модификации возвращаемого ответа.```js
router.defineRoute({
// ...
handler(ctx) {
return 'Hello world!';
},
postHandler(ctx, data) {
// после обработчика маршрута
return data.toUpperCase(); // HELLO WORLD!
},
});
```### Глобальные хуки
Экземпляр роутера `TrieRouter` позволяет задать глобальные хуки, которые
имеют более высокий приоритет перед хуками маршрута, и вызываются
в первую очередь.- `preHandler` выполняется перед вызовом обработчика каждого маршрута
- `postHandler` выполняется после вызова обработчика каждого маршрутаДобавить глобальные хуки можно методом `addHook` экземпляра роутера,
где первым параметром передается название хука, а вторым его функция.```js
router.addHook('preHandler', (ctx) => {
// перед обработчиком маршрута
});router.addHook('postHandler', (ctx, data) => {
// после обработчика маршрута
});
```Аналогично хукам маршрута, если глобальный хук возвращает значение
отличное от `undefined` и `null`, то такое значение будет использовано
как ответ сервера.## Отладка
Установка переменной `DEBUG` включает вывод логов.
```bash
DEBUG=jsTrieRouter* npm run test
```## Тестирование
```bash
npm run test
```## Лицензия
MIT