0.2.9 • Published 5 months ago

@e22m4u/ts-rest-router v0.2.9

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

@e22m4u/ts-rest-router

REST маршрутизатор на основе контроллеров для TypeScript.

Основные возможности

  • Декларативное определение маршрутов через декораторы.
  • Типизированные параметры запросов (body, query, params).
  • Поддержка middleware до и после обработки запроса.
  • Валидация входящих данных.
  • Поддержка всех HTTP методов (GET, POST, PUT, PATCH и DELETE).

Содержание

Установка

npm install @e22m4u/ts-rest-router

Поддержка декораторов

Для включения поддержки декораторов, добавьте указанные ниже опции в файл tsconfig.json вашего проекта.

{
  "emitDecoratorMetadata": true,
  "experimentalDecorators": true
}

Базовый пример

Создание контроллера и методов.

import {DataType} from '@e22m4u/ts-rest-router';
import {getAction} from '@e22m4u/ts-rest-router';
import {postAction} from '@e22m4u/ts-rest-router';
import {requestField} from '@e22m4u/ts-rest-router';
import {restController} from '@e22m4u/ts-rest-router';

// объявление контроллера
// и базового пути /users
@restController('users')
class UserController {
  // объявление метода POST /users/login
  // (использует базовый путь контроллера)
  @postAction('login')
  async login(
    // инъекция значений указанных полей
    // извлеизвлекаемых из тела запроса
    @requestField('username') username?: string,
    @requestField('password') password?: string,
  ) {
    // так как метод возвращает объект,
    // результат будет представлен как
    // "Content-Type: application/json"
    return {
      id: 1,
      firstName: 'John',
      lastName: 'Doe',
    };
  }
}

Регистрация контроллеров и запуск сервера.

import http from 'http';
import {RestRouter} from '@e22m4u/ts-rest-router';

// создание маршрутизатора и регистрация контроллеров
const router = new RestRouter();
router.registerController(UserController);
router.registerController(ProductController);

// создание сервера и регистрация обработчика запросов
const server = new http.Server();
server.on('request', router.requestListener);

// запуск сервера
server.listen('8080', '0.0.0.0', () => {
  console.log(`Server is running on http://localhost:8080`);
});

Валидация

Указанные ниже декораторы используются для инъекции соответствующих параметров запроса в качестве аргументов метода контроллера. Каждый из указанных декораторов имеет параметр schemaOrType, в котором определяется тип ожидаемого значения или схема для проверки данных.

  • @requestParam(name: string, schemaOrType?: DataSchema | DataType)
    - извлечение URL параметра по названию;
  • @requestQuery(name: string, schemaOrType?: DataSchema | DataType)
    - извлечение query параметра по названию;
  • @requestBody(schemaOrType?: DataSchema | DataType)
    - извлечение тела запроса;
  • @requestField(name: string, schemaOrType?: DataSchema | DataType)
    - извлечение свойства из тела запроса;
  • @requestHeader(name: string, schemaOrType?: DataSchema | DataType)
    - извлечение заголовка запроса по названию;
  • @requestCookie(name: string, schemaOrType?: DataSchema | DataType)
    - извлечение cookie запроса по названию;

Проверка входящих данных выполняется встроенным модулем @e22m4u/ts-data-schema (не требует установки). Ниже приводятся константы для определения допустимых типов извлекаемого значения.

  • DataType.ANY - принимает любой тип
  • DataType.STRING - строковые значения
  • DataType.NUMBER - числовые значения
  • DataType.BOOLEAN - логические значения
  • DataType.ARRAY - массивы
  • DataType.OBJECT - объекты (не экземпляры)

Для определения дополнительных условий, используется объект DataSchema, с помощью которого можно определить структуру ожидаемого объекта, допустимые элементы массива, функции-валидаторы и другие ограничения входящих данных.

type DataSchema = {
  type: DataType;
  items?: DataSchema;
  properties?: {[key: string]: DataSchema};
  required?: boolean;
  validate?: CallableValidator | CallableValidator[];
  default?: unknown;
}

Пример проверки передаваемого объекта методом POST:

import {DataType} from '@e22m4u/ts-rest-router';
import {getAction} from '@e22m4u/ts-rest-router';
import {postAction} from '@e22m4u/ts-rest-router';
import {requestField} from '@e22m4u/ts-rest-router';
import {restController} from '@e22m4u/ts-rest-router';

@restController('users')
class UserController {
  @postAction()                        // POST /users
  async create(
    @requestBody({                     // декоратор тела запроса
      type: DataType.OBJECT,           // в теле запроса ожидается объект
      properties: {
        name: {                        // схема свойства "name"
          type: DataType.STRING,       // свойство должно содержать строку
          required: true,              // свойство не может содержать undefined или null
          validate: v => v.length > 2, // проверка длины строки
        },
        age: {                         // схема свойства "age"
          type: DataType.NUMBER,       // свойство должно являться числом
        }
      },
    })
    body: {name: string, age?: number},
  ) {
    return {
      id: 1,
      name: body.name,
      age: body.age,
    };
  }
}

Декораторы

Контроллер и методы:

  • @restController - определяет класс как контроллер;
  • @restAction - базовый декоратор для методов;
  • @getAction - метод GET;
  • @postAction - метод POST;
  • @putAction - метод PUT;
  • @patchAction - метод PATCH;
  • @deleteAction - метод DELETE;

Хуки запроса:

  • @beforeAction - middleware перед обработкой запроса;
  • @afterAction - middleware после обработки запроса;

Параметры запроса:

  • @requestParam - определенный URL параметр;
  • @requestParams - все параметры URL как объект;
  • @requestQuery - определенный query параметр;
  • @requestQueries - все query параметры как объект;
  • @requestBody - тело запроса;
  • @requestField - поле в теле запроса;
  • @requestHeader - определенный заголовок запроса;
  • @requestHeaders - все заголовки запроса как объект;
  • @requestCookie - определенный cookie запроса;
  • @requestCookies - все cookies запроса как объект;
  • @requestContext - доступ к контексту запроса;
  • @requestData - доступ к данным запроса;
  • @httpRequest - экземпляр IncomingMessage;
  • @httpResponse - экземпляр ServerResponse;

@restController(options?: ControllerOptions)

Определение контроллера.

@restController()
class UserController {
  // ...
}

Определение базового пути.

@restController('users')
class UserController {
  // ...
}

Дополнительные параметры декоратора.

@restController({
  path: 'api',               // базовый путь
  before: [authMiddleware],  // middleware до обработки запроса
  after: [loggerMiddleware], // middleware после обработки запроса
})
class UserController {
  // ...
}

@getAction(path: string, options?: ActionOptions)

Определение метода GET.

@restController('users')
class UserController {
  @getAction('whoAmI')   // маршрут GET /users/whoAmI
  async whoAmI() {
    return {              // если метод возвращает объект,
      name: 'John',       // то результат будет представлен
      surname: 'Doe',     // как "Content-Type: application/json"
    };
  }
}

Дополнительные параметры декоратора.

@restController('users')
class UserController {
  @getAction('whoAmI', {      // маршрут GET /users/whoAmI
    before: [authMiddleware],  // middleware до обработки запроса
    after: [loggerMiddleware], // middleware после обработки запроса
  })
  async whoAmI() {
    return {
      name: 'John',
      surname: 'Doe',
    };
  }
}

@requestContext(propertyName?: string)

Доступ к контексту запроса.

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

@restController('users')
class UserController {
  @getAction(':id')
  findById(
    @requestContext()          // инъекция контекста запроса
    ctx: RequestContext,       // в качестве аргумента
  ) {
    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"
    // ...
  }
}

Доступ к свойствам контекста.

import {ServerResponse} from 'http';
import {IncomingMessage} from 'http';

@restController('/users')  // путь контроллера
class UserController {     // класс контроллера
  @getAction('/:id')       // маршрут GET /users/:id
  findById(
    @requestContext('req') // декоратор контекста запроса
    req: IncomingMessage,  // включающий свойство "req"
    @requestContext('res') // декоратор контекста запроса
    res: ServerResponse,   // включающий свойство "res"
  ) {
    console.log(req);      // IncomingMessage
    console.log(res);      // ServerResponse
  }
}

Свойства контекста:

  • container: ServiceContainer экземпляр сервис-контейнера
  • 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 тело запроса

Отладка

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

DEBUG=tsRestRouter* npm run test

Тесты

npm run test

Лицензия

MIT

0.2.9

5 months ago

0.2.8

5 months ago

0.2.7

5 months ago

0.2.6

5 months ago

0.2.5

5 months ago

0.2.4

5 months ago

0.2.3

5 months ago

0.2.2

5 months ago

0.2.1

6 months ago

0.2.0

6 months ago

0.1.2

6 months ago

0.1.1

10 months ago

0.1.0

10 months ago

0.0.7

10 months ago

0.0.6

11 months ago

0.0.5

11 months ago

0.0.4

11 months ago

0.0.3

12 months ago

0.0.2

12 months ago