@e22m4u/ts-rest-router 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +129 -34
  2. package/dist/cjs/index.cjs +87 -23
  3. package/dist/esm/controller-registry.js +9 -4
  4. package/dist/esm/decorators/after-action/after-action-reflector.spec.js +0 -1
  5. package/dist/esm/decorators/before-action/before-action-reflector.spec.js +0 -1
  6. package/dist/esm/decorators/index.d.ts +1 -0
  7. package/dist/esm/decorators/index.js +1 -0
  8. package/dist/esm/decorators/request-context/request-context-reflector.spec.js +0 -1
  9. package/dist/esm/decorators/request-data/request-data-decorator.d.ts +11 -11
  10. package/dist/esm/decorators/request-data/request-data-decorator.js +3 -3
  11. package/dist/esm/decorators/request-data/request-data-reflector.spec.js +0 -1
  12. package/dist/esm/decorators/response-body/index.d.ts +3 -0
  13. package/dist/esm/decorators/response-body/index.js +3 -0
  14. package/dist/esm/decorators/response-body/response-body-decorator.d.ts +9 -0
  15. package/dist/esm/decorators/response-body/response-body-decorator.js +23 -0
  16. package/dist/esm/decorators/response-body/response-body-decorator.spec.d.ts +1 -0
  17. package/dist/esm/decorators/response-body/response-body-decorator.spec.js +61 -0
  18. package/dist/esm/decorators/response-body/response-body-metadata.d.ts +16 -0
  19. package/dist/esm/decorators/response-body/response-body-metadata.js +5 -0
  20. package/dist/esm/decorators/response-body/response-body-reflector.d.ts +22 -0
  21. package/dist/esm/decorators/response-body/response-body-reflector.js +29 -0
  22. package/dist/esm/decorators/response-body/response-body-reflector.spec.d.ts +1 -0
  23. package/dist/esm/decorators/response-body/response-body-reflector.spec.js +58 -0
  24. package/dist/esm/decorators/rest-action/rest-action-reflector.spec.js +0 -1
  25. package/dist/esm/decorators/rest-controller/rest-controller-reflector.spec.js +0 -1
  26. package/eslint.config.js +1 -1
  27. package/package.json +15 -15
  28. package/src/controller-registry.spec.ts +85 -27
  29. package/src/controller-registry.ts +13 -4
  30. package/src/debuggable-service.spec.ts +0 -1
  31. package/src/decorators/after-action/after-action-reflector.spec.ts +0 -1
  32. package/src/decorators/before-action/before-action-reflector.spec.ts +0 -1
  33. package/src/decorators/index.ts +1 -0
  34. package/src/decorators/request-context/request-context-reflector.spec.ts +0 -1
  35. package/src/decorators/request-data/request-data-decorator.ts +3 -11
  36. package/src/decorators/request-data/request-data-reflector.spec.ts +0 -1
  37. package/src/decorators/response-body/index.ts +3 -0
  38. package/src/decorators/response-body/response-body-decorator.spec.ts +40 -0
  39. package/src/decorators/response-body/response-body-decorator.ts +43 -0
  40. package/src/decorators/response-body/response-body-metadata.ts +20 -0
  41. package/src/decorators/response-body/response-body-reflector.spec.ts +59 -0
  42. package/src/decorators/response-body/response-body-reflector.ts +41 -0
  43. package/src/decorators/rest-action/rest-action-reflector.spec.ts +0 -1
  44. package/src/decorators/rest-controller/rest-controller-reflector.spec.ts +0 -1
package/README.md CHANGED
@@ -10,6 +10,16 @@ REST маршрутизатор на основе контроллеров дл
10
10
  - Валидация входящих данных.
11
11
  - Поддержка всех HTTP методов (GET, POST, PUT, PATCH и DELETE).
12
12
 
13
+ ## Содержание
14
+
15
+ - [Установка](#установка)
16
+ - [Поддержка декораторов](#поддержка-декораторов)
17
+ - [Базовый пример](#базовый-пример)
18
+ - [Валидация](#валидация)
19
+ - [Декораторы](#декораторы)
20
+ - [Отладка](#отладка)
21
+ - [Тесты](#тесты)
22
+
13
23
  ## Установка
14
24
 
15
25
  ```bash
@@ -28,7 +38,7 @@ npm install @e22m4u/ts-rest-router
28
38
  }
29
39
  ```
30
40
 
31
- ## Базовое использование
41
+ ## Базовый пример
32
42
 
33
43
  Создание контроллера и методов.
34
44
 
@@ -39,24 +49,25 @@ import {postAction} from '@e22m4u/ts-rest-router';
39
49
  import {requestField} from '@e22m4u/ts-rest-router';
40
50
  import {restController} from '@e22m4u/ts-rest-router';
41
51
 
42
- @restController('/users') // путь контроллера
43
- class UserController { // класс контроллера
44
- @postAction('/login') // метод POST /users/login
52
+ // объявление контроллера
53
+ // и базового пути /users
54
+ @restController('users')
55
+ class UserController {
56
+ // объявление метода POST /users/login
57
+ // (использует базовый путь контроллера)
58
+ @postAction('login')
45
59
  async login(
46
- @requestField('username', { // поле "username" в теле запроса
47
- type: DataType.STRING, // тип параметра допускает только строки
48
- required: true, // параметр является обязательным
49
- })
50
- username: string,
51
- @requestField('password', { // поле "password" в теле запроса
52
- type: DataType.STRING, // тип параметра допускает только строки
53
- required: true, // параметр является обязательным
54
- })
55
- password: string,
60
+ // инъекция значений указанных полей
61
+ // извлеизвлекаемых из тела запроса
62
+ @requestField('username') username?: string,
63
+ @requestField('password') password?: string,
56
64
  ) {
57
- return { // если метод возвращает объект,
58
- id: '123', // то результат будет представлен как
59
- firstName: 'John', // "Content-Type: application/json"
65
+ // так как метод возвращает объект,
66
+ // результат будет представлен как
67
+ // "Content-Type: application/json"
68
+ return {
69
+ id: 1,
70
+ firstName: 'John',
60
71
  lastName: 'Doe',
61
72
  };
62
73
  }
@@ -84,6 +95,90 @@ server.listen('8080', '0.0.0.0', () => {
84
95
  });
85
96
  ```
86
97
 
98
+ ## Валидация
99
+
100
+ Указанные ниже декораторы используются для инъекции соответствующих параметров
101
+ запроса в качестве аргументов метода контроллера. Каждый из указанных декораторов
102
+ имеет параметр `schemaOrType`, в котором определяется тип ожидаемого значения
103
+ или схема для проверки данных.
104
+
105
+ - `@requestParam(name: string, schemaOrType?: DataSchema | DataType)`
106
+ *- извлечение URL параметра по названию;*
107
+ - `@requestQuery(name: string, schemaOrType?: DataSchema | DataType)`
108
+ *- извлечение query параметра по названию;*
109
+ - `@requestBody(schemaOrType?: DataSchema | DataType)`
110
+ *- извлечение тела запроса;*
111
+ - `@requestField(name: string, schemaOrType?: DataSchema | DataType)`
112
+ *- извлечение свойства из тела запроса;*
113
+ - `@requestHeader(name: string, schemaOrType?: DataSchema | DataType)`
114
+ *- извлечение заголовка запроса по названию;*
115
+ - `@requestCookie(name: string, schemaOrType?: DataSchema | DataType)`
116
+ *- извлечение cookie запроса по названию;*
117
+
118
+ Проверка входящих данных выполняется встроенным модулем
119
+ [@e22m4u/ts-data-schema](https://www.npmjs.com/package/@e22m4u/ts-data-schema)
120
+ (не требует установки). Ниже приводятся константы для определения допустимых
121
+ типов извлекаемого значения.
122
+
123
+ - `DataType.ANY` - принимает любой тип
124
+ - `DataType.STRING` - строковые значения
125
+ - `DataType.NUMBER` - числовые значения
126
+ - `DataType.BOOLEAN` - логические значения
127
+ - `DataType.ARRAY` - массивы
128
+ - `DataType.OBJECT` - объекты (не экземпляры)
129
+
130
+ Для определения дополнительных условий, используется объект `DataSchema`,
131
+ с помощью которого можно определить структуру ожидаемого объекта, допустимые
132
+ элементы массива, функции-валидаторы и другие ограничения входящих данных.
133
+
134
+ ```ts
135
+ type DataSchema = {
136
+ type: DataType;
137
+ items?: DataSchema;
138
+ properties?: {[key: string]: DataSchema};
139
+ required?: boolean;
140
+ validate?: CallableValidator | CallableValidator[];
141
+ default?: unknown;
142
+ }
143
+ ```
144
+
145
+ Пример проверки передаваемого объекта методом POST:
146
+
147
+ ```ts
148
+ import {DataType} from '@e22m4u/ts-rest-router';
149
+ import {getAction} from '@e22m4u/ts-rest-router';
150
+ import {postAction} from '@e22m4u/ts-rest-router';
151
+ import {requestField} from '@e22m4u/ts-rest-router';
152
+ import {restController} from '@e22m4u/ts-rest-router';
153
+
154
+ @restController('users')
155
+ class UserController {
156
+ @postAction() // POST /users
157
+ async create(
158
+ @requestBody({ // декоратор тела запроса
159
+ type: DataType.OBJECT, // в теле запроса ожидается объект
160
+ properties: {
161
+ name: { // схема свойства "name"
162
+ type: DataType.STRING, // свойство должно содержать строку
163
+ required: true, // свойство не может содержать undefined или null
164
+ validate: v => v.length > 2, // проверка длины строки
165
+ },
166
+ age: { // схема свойства "age"
167
+ type: DataType.NUMBER, // свойство должно являться числом
168
+ }
169
+ },
170
+ })
171
+ body: {name: string, age?: number},
172
+ ) {
173
+ return {
174
+ id: 1,
175
+ name: body.name,
176
+ age: body.age,
177
+ };
178
+ }
179
+ }
180
+ ```
181
+
87
182
  ## Декораторы
88
183
 
89
184
  Контроллер и методы:
@@ -125,16 +220,16 @@ server.listen('8080', '0.0.0.0', () => {
125
220
  ```ts
126
221
  @restController()
127
222
  class UserController {
128
- // методы контроллера
223
+ // ...
129
224
  }
130
225
  ```
131
226
 
132
- Определение пути контроллера.
227
+ Определение базового пути.
133
228
 
134
229
  ```ts
135
- @restController('/users') // путь контроллера
230
+ @restController('users')
136
231
  class UserController {
137
- // методы контроллера
232
+ // ...
138
233
  }
139
234
  ```
140
235
 
@@ -142,12 +237,12 @@ class UserController {
142
237
 
143
238
  ```ts
144
239
  @restController({
145
- path: '/api', // путь контроллера
240
+ path: 'api', // базовый путь
146
241
  before: [authMiddleware], // middleware до обработки запроса
147
242
  after: [loggerMiddleware], // middleware после обработки запроса
148
243
  })
149
244
  class UserController {
150
- // методы контроллера
245
+ // ...
151
246
  }
152
247
  ```
153
248
 
@@ -156,9 +251,9 @@ class UserController {
156
251
  Определение метода GET.
157
252
 
158
253
  ```ts
159
- @restController('/users') // путь контроллера
160
- class UserController { // класс контроллера
161
- @getAction('/whoAmI') // маршрут GET /users/whoAmI
254
+ @restController('users')
255
+ class UserController {
256
+ @getAction('whoAmI') // маршрут GET /users/whoAmI
162
257
  async whoAmI() {
163
258
  return { // если метод возвращает объект,
164
259
  name: 'John', // то результат будет представлен
@@ -171,9 +266,9 @@ class UserController { // класс контроллера
171
266
  Дополнительные параметры декоратора.
172
267
 
173
268
  ```ts
174
- @restController('/users') // путь контроллера
175
- class UserController { // класс контроллера
176
- @getAction('/whoAmI', { // маршрут GET /users/whoAmI
269
+ @restController('users')
270
+ class UserController {
271
+ @getAction('whoAmI', { // маршрут GET /users/whoAmI
177
272
  before: [authMiddleware], // middleware до обработки запроса
178
273
  after: [loggerMiddleware], // middleware после обработки запроса
179
274
  })
@@ -193,12 +288,12 @@ class UserController { // класс контроллера
193
288
  ```ts
194
289
  import {RequestContext} from '@e22m4u/js-trie-router';
195
290
 
196
- @restController('/users') // путь контроллера
197
- class UserController { // класс контроллера
198
- @getAction('/:id') // маршрут GET /users/:id
291
+ @restController('users')
292
+ class UserController {
293
+ @getAction(':id')
199
294
  findById(
200
- @requestContext() // включениее контекста запроса
201
- ctx: RequestContext, // в качестве параметра метода
295
+ @requestContext() // инъекция контекста запроса
296
+ ctx: RequestContext, // в качестве аргумента
202
297
  ) {
203
298
  console.log(ctx.req); // IncomingMessage
204
299
  console.log(ctx.res); // ServerResponse
@@ -29,11 +29,13 @@ __export(index_exports, {
29
29
  NotAControllerError: () => NotAControllerError,
30
30
  REQUEST_CONTEXT_METADATA_KEY: () => REQUEST_CONTEXT_METADATA_KEY,
31
31
  REQUEST_DATA_METADATA_KEY: () => REQUEST_DATA_METADATA_KEY,
32
+ RESPONSE_BODY_METADATA_KEY: () => RESPONSE_BODY_METADATA_KEY,
32
33
  REST_ACTIONS_METADATA_KEY: () => REST_ACTIONS_METADATA_KEY,
33
34
  REST_CONTROLLER_METADATA_KEY: () => REST_CONTROLLER_METADATA_KEY,
34
35
  RequestContextReflector: () => RequestContextReflector,
35
36
  RequestDataReflector: () => RequestDataReflector,
36
37
  RequestDataSource: () => RequestDataSource,
38
+ ResponseBodyReflector: () => ResponseBodyReflector,
37
39
  RestActionReflector: () => RestActionReflector,
38
40
  RestControllerReflector: () => RestControllerReflector,
39
41
  RestRouter: () => RestRouter,
@@ -60,6 +62,7 @@ __export(index_exports, {
60
62
  requestParams: () => requestParams,
61
63
  requestQueries: () => requestQueries,
62
64
  requestQuery: () => requestQuery,
65
+ responseBody: () => responseBody,
63
66
  restAction: () => restAction,
64
67
  restController: () => restController,
65
68
  toCamelCase: () => toCamelCase
@@ -281,11 +284,11 @@ var RequestDataReflector = _RequestDataReflector;
281
284
 
282
285
  // dist/esm/decorators/request-data/request-data-decorator.js
283
286
  function requestData(options) {
284
- return function(target, propertyKey, indexOrDescriptor) {
285
- const decoratorType = (0, import_ts_reflector8.getDecoratorTargetType)(target, propertyKey, indexOrDescriptor);
287
+ return function(target, propertyKey, index) {
288
+ const decoratorType = (0, import_ts_reflector8.getDecoratorTargetType)(target, propertyKey, index);
286
289
  if (decoratorType !== import_ts_reflector7.DecoratorTargetType.INSTANCE_METHOD_PARAMETER)
287
290
  throw new Error("@requestData decorator is only supported on an instance method parameter.");
288
- RequestDataReflector.setMetadata(options, target.constructor, indexOrDescriptor, propertyKey);
291
+ RequestDataReflector.setMetadata(options, target.constructor, index, propertyKey);
289
292
  };
290
293
  }
291
294
  __name(requestData, "requestData");
@@ -437,16 +440,70 @@ function beforeAction(middleware) {
437
440
  }
438
441
  __name(beforeAction, "beforeAction");
439
442
 
440
- // dist/esm/decorators/rest-controller/rest-controller-metadata.js
443
+ // dist/esm/decorators/response-body/response-body-metadata.js
441
444
  var import_ts_reflector17 = require("@e22m4u/ts-reflector");
442
- var REST_CONTROLLER_METADATA_KEY = new import_ts_reflector17.MetadataKey("restControllerMetadataKey");
445
+ var RESPONSE_BODY_METADATA_KEY = new import_ts_reflector17.MetadataKey("responseBodyMetadataKey");
443
446
 
444
- // dist/esm/decorators/rest-controller/rest-controller-decorator.js
447
+ // dist/esm/decorators/response-body/response-body-decorator.js
445
448
  var import_ts_reflector19 = require("@e22m4u/ts-reflector");
446
449
  var import_ts_reflector20 = require("@e22m4u/ts-reflector");
447
450
 
448
- // dist/esm/decorators/rest-controller/rest-controller-reflector.js
451
+ // dist/esm/decorators/response-body/response-body-reflector.js
449
452
  var import_ts_reflector18 = require("@e22m4u/ts-reflector");
453
+ var _ResponseBodyReflector = class _ResponseBodyReflector {
454
+ /**
455
+ * Set metadata.
456
+ *
457
+ * @param metadata
458
+ * @param target
459
+ * @param propertyKey
460
+ */
461
+ static setMetadata(metadata, target, propertyKey) {
462
+ const oldMap = import_ts_reflector18.Reflector.getOwnMetadata(RESPONSE_BODY_METADATA_KEY, target);
463
+ const newMap = new Map(oldMap);
464
+ newMap.set(propertyKey, metadata);
465
+ import_ts_reflector18.Reflector.defineMetadata(RESPONSE_BODY_METADATA_KEY, newMap, target);
466
+ }
467
+ /**
468
+ * Get metadata.
469
+ *
470
+ * @param target
471
+ */
472
+ static getMetadata(target) {
473
+ const metadata = import_ts_reflector18.Reflector.getOwnMetadata(RESPONSE_BODY_METADATA_KEY, target);
474
+ return metadata ?? /* @__PURE__ */ new Map();
475
+ }
476
+ };
477
+ __name(_ResponseBodyReflector, "ResponseBodyReflector");
478
+ var ResponseBodyReflector = _ResponseBodyReflector;
479
+
480
+ // dist/esm/decorators/response-body/response-body-decorator.js
481
+ function responseBody(schemaOrType) {
482
+ return function(target, propertyKey, descriptor) {
483
+ const decoratorType = (0, import_ts_reflector20.getDecoratorTargetType)(target, propertyKey, descriptor);
484
+ if (decoratorType !== import_ts_reflector19.DecoratorTargetType.INSTANCE_METHOD)
485
+ throw new Error("@responseBody decorator is only supported on an instance method.");
486
+ let schema;
487
+ if (typeof schemaOrType === "object") {
488
+ schema = schemaOrType;
489
+ } else if (typeof schemaOrType === "string") {
490
+ schema = { type: schemaOrType };
491
+ }
492
+ ResponseBodyReflector.setMetadata(schema ? { schema } : {}, target.constructor, propertyKey);
493
+ };
494
+ }
495
+ __name(responseBody, "responseBody");
496
+
497
+ // dist/esm/decorators/rest-controller/rest-controller-metadata.js
498
+ var import_ts_reflector21 = require("@e22m4u/ts-reflector");
499
+ var REST_CONTROLLER_METADATA_KEY = new import_ts_reflector21.MetadataKey("restControllerMetadataKey");
500
+
501
+ // dist/esm/decorators/rest-controller/rest-controller-decorator.js
502
+ var import_ts_reflector23 = require("@e22m4u/ts-reflector");
503
+ var import_ts_reflector24 = require("@e22m4u/ts-reflector");
504
+
505
+ // dist/esm/decorators/rest-controller/rest-controller-reflector.js
506
+ var import_ts_reflector22 = require("@e22m4u/ts-reflector");
450
507
  var _RestControllerReflector = class _RestControllerReflector {
451
508
  /**
452
509
  * Set metadata.
@@ -455,7 +512,7 @@ var _RestControllerReflector = class _RestControllerReflector {
455
512
  * @param target
456
513
  */
457
514
  static setMetadata(metadata, target) {
458
- return import_ts_reflector18.Reflector.defineMetadata(REST_CONTROLLER_METADATA_KEY, metadata, target);
515
+ return import_ts_reflector22.Reflector.defineMetadata(REST_CONTROLLER_METADATA_KEY, metadata, target);
459
516
  }
460
517
  /**
461
518
  * Get metadata.
@@ -463,7 +520,7 @@ var _RestControllerReflector = class _RestControllerReflector {
463
520
  * @param target
464
521
  */
465
522
  static getMetadata(target) {
466
- return import_ts_reflector18.Reflector.getOwnMetadata(REST_CONTROLLER_METADATA_KEY, target);
523
+ return import_ts_reflector22.Reflector.getOwnMetadata(REST_CONTROLLER_METADATA_KEY, target);
467
524
  }
468
525
  };
469
526
  __name(_RestControllerReflector, "RestControllerReflector");
@@ -472,8 +529,8 @@ var RestControllerReflector = _RestControllerReflector;
472
529
  // dist/esm/decorators/rest-controller/rest-controller-decorator.js
473
530
  function restController(pathOrOptions, options) {
474
531
  return function(target) {
475
- const decoratorType = (0, import_ts_reflector20.getDecoratorTargetType)(target);
476
- if (decoratorType !== import_ts_reflector19.DecoratorTargetType.CONSTRUCTOR)
532
+ const decoratorType = (0, import_ts_reflector24.getDecoratorTargetType)(target);
533
+ if (decoratorType !== import_ts_reflector23.DecoratorTargetType.CONSTRUCTOR)
477
534
  throw new Error("@restController decorator is only supported on a class.");
478
535
  if (typeof pathOrOptions === "string") {
479
536
  if (!options) {
@@ -490,15 +547,15 @@ function restController(pathOrOptions, options) {
490
547
  __name(restController, "restController");
491
548
 
492
549
  // dist/esm/decorators/request-context/request-context-metadata.js
493
- var import_ts_reflector21 = require("@e22m4u/ts-reflector");
494
- var REQUEST_CONTEXT_METADATA_KEY = new import_ts_reflector21.MetadataKey("requestContextMetadataKey");
550
+ var import_ts_reflector25 = require("@e22m4u/ts-reflector");
551
+ var REQUEST_CONTEXT_METADATA_KEY = new import_ts_reflector25.MetadataKey("requestContextMetadataKey");
495
552
 
496
553
  // dist/esm/decorators/request-context/request-context-decorator.js
497
- var import_ts_reflector23 = require("@e22m4u/ts-reflector");
498
- var import_ts_reflector24 = require("@e22m4u/ts-reflector");
554
+ var import_ts_reflector27 = require("@e22m4u/ts-reflector");
555
+ var import_ts_reflector28 = require("@e22m4u/ts-reflector");
499
556
 
500
557
  // dist/esm/decorators/request-context/request-context-reflector.js
501
- var import_ts_reflector22 = require("@e22m4u/ts-reflector");
558
+ var import_ts_reflector26 = require("@e22m4u/ts-reflector");
502
559
  var _RequestContextReflector = class _RequestContextReflector {
503
560
  /**
504
561
  * Set metadata.
@@ -509,10 +566,10 @@ var _RequestContextReflector = class _RequestContextReflector {
509
566
  * @param propertyKey
510
567
  */
511
568
  static setMetadata(metadata, target, index, propertyKey) {
512
- const oldMap = import_ts_reflector22.Reflector.getOwnMetadata(REQUEST_CONTEXT_METADATA_KEY, target, propertyKey);
569
+ const oldMap = import_ts_reflector26.Reflector.getOwnMetadata(REQUEST_CONTEXT_METADATA_KEY, target, propertyKey);
513
570
  const newMap = new Map(oldMap);
514
571
  newMap.set(index, metadata);
515
- import_ts_reflector22.Reflector.defineMetadata(REQUEST_CONTEXT_METADATA_KEY, newMap, target, propertyKey);
572
+ import_ts_reflector26.Reflector.defineMetadata(REQUEST_CONTEXT_METADATA_KEY, newMap, target, propertyKey);
516
573
  }
517
574
  /**
518
575
  * Get metadata.
@@ -521,7 +578,7 @@ var _RequestContextReflector = class _RequestContextReflector {
521
578
  * @param propertyKey
522
579
  */
523
580
  static getMetadata(target, propertyKey) {
524
- const metadata = import_ts_reflector22.Reflector.getOwnMetadata(REQUEST_CONTEXT_METADATA_KEY, target, propertyKey);
581
+ const metadata = import_ts_reflector26.Reflector.getOwnMetadata(REQUEST_CONTEXT_METADATA_KEY, target, propertyKey);
525
582
  return metadata ?? /* @__PURE__ */ new Map();
526
583
  }
527
584
  };
@@ -531,8 +588,8 @@ var RequestContextReflector = _RequestContextReflector;
531
588
  // dist/esm/decorators/request-context/request-context-decorator.js
532
589
  function requestContext(propertyName) {
533
590
  return function(target, propertyKey, indexOrDescriptor) {
534
- const decoratorType = (0, import_ts_reflector24.getDecoratorTargetType)(target, propertyKey, indexOrDescriptor);
535
- if (decoratorType !== import_ts_reflector23.DecoratorTargetType.INSTANCE_METHOD_PARAMETER)
591
+ const decoratorType = (0, import_ts_reflector28.getDecoratorTargetType)(target, propertyKey, indexOrDescriptor);
592
+ if (decoratorType !== import_ts_reflector27.DecoratorTargetType.INSTANCE_METHOD_PARAMETER)
536
593
  throw new Error("@requestContext decorator is only supported on an instance method parameter.");
537
594
  RequestContextReflector.setMetadata({ property: propertyName }, target.constructor, indexOrDescriptor, propertyKey);
538
595
  };
@@ -548,6 +605,7 @@ function httpResponse() {
548
605
  __name(httpResponse, "httpResponse");
549
606
 
550
607
  // dist/esm/controller-registry.js
608
+ var import_ts_data_schema4 = require("@e22m4u/ts-data-schema");
551
609
  var _ControllerRegistry = class _ControllerRegistry extends DebuggableService {
552
610
  /**
553
611
  * Controllers.
@@ -828,6 +886,7 @@ var _ControllerRegistry = class _ControllerRegistry extends DebuggableService {
828
886
  const requestContextMetadataMap = RequestContextReflector.getMetadata(controllerCtor, actionName);
829
887
  const requestDataMetadataMap = RequestDataReflector.getMetadata(controllerCtor, actionName);
830
888
  const argsNumber = controllerCtor.prototype[actionName].length;
889
+ const defaultsApplier = this.getService(import_ts_data_schema4.DefaultValuesApplier);
831
890
  const dataTypeCaster = this.getService(import_ts_data_schema3.DataTypeCaster);
832
891
  const dataValidator = this.getService(import_ts_data_schema2.DataValidator);
833
892
  return (requestContext2) => {
@@ -872,13 +931,15 @@ var _ControllerRegistry = class _ControllerRegistry extends DebuggableService {
872
931
  }
873
932
  debug("Request data source is %v.", requestDataMd.source);
874
933
  if (requestDataMd.schema) {
934
+ data = defaultsApplier.applyDefaultValuesIfNeeded(data, requestDataMd.schema, requestDataMd.source);
935
+ debug("Default values applied.");
875
936
  data = dataTypeCaster.cast(data, requestDataMd.schema, {
876
937
  noTypeCastError: true,
877
938
  sourcePath: requestDataMd.source
878
939
  });
879
- debug("Data type casting is passed.");
940
+ debug("Data type casting applied.");
880
941
  dataValidator.validate(data, requestDataMd.schema, requestDataMd.source);
881
- debug("Data validation is passed.");
942
+ debug("Data validation passed.");
882
943
  }
883
944
  if (requestDataMd.property == null) {
884
945
  debug("Request data property is not specified.");
@@ -934,11 +995,13 @@ var RestRouter = _RestRouter;
934
995
  NotAControllerError,
935
996
  REQUEST_CONTEXT_METADATA_KEY,
936
997
  REQUEST_DATA_METADATA_KEY,
998
+ RESPONSE_BODY_METADATA_KEY,
937
999
  REST_ACTIONS_METADATA_KEY,
938
1000
  REST_CONTROLLER_METADATA_KEY,
939
1001
  RequestContextReflector,
940
1002
  RequestDataReflector,
941
1003
  RequestDataSource,
1004
+ ResponseBodyReflector,
942
1005
  RestActionReflector,
943
1006
  RestControllerReflector,
944
1007
  RestRouter,
@@ -965,6 +1028,7 @@ var RestRouter = _RestRouter;
965
1028
  requestParams,
966
1029
  requestQueries,
967
1030
  requestQuery,
1031
+ responseBody,
968
1032
  restAction,
969
1033
  restController,
970
1034
  toCamelCase
@@ -8,6 +8,7 @@ import { DebuggableService } from './debuggable-service.js';
8
8
  import { RestActionReflector } from './decorators/index.js';
9
9
  import { RequestDataReflector } from './decorators/index.js';
10
10
  import { AfterActionReflector } from './decorators/index.js';
11
+ import { DefaultValuesApplier } from '@e22m4u/ts-data-schema';
11
12
  import { BeforeActionReflector } from './decorators/index.js';
12
13
  import { RestControllerReflector } from './decorators/index.js';
13
14
  import { RequestContextReflector } from './decorators/index.js';
@@ -320,6 +321,7 @@ export class ControllerRegistry extends DebuggableService {
320
321
  const requestContextMetadataMap = RequestContextReflector.getMetadata(controllerCtor, actionName);
321
322
  const requestDataMetadataMap = RequestDataReflector.getMetadata(controllerCtor, actionName);
322
323
  const argsNumber = controllerCtor.prototype[actionName].length;
324
+ const defaultsApplier = this.getService(DefaultValuesApplier);
323
325
  const dataTypeCaster = this.getService(DataTypeCaster);
324
326
  const dataValidator = this.getService(DataValidator);
325
327
  return (requestContext) => {
@@ -378,16 +380,19 @@ export class ControllerRegistry extends DebuggableService {
378
380
  break;
379
381
  }
380
382
  debug('Request data source is %v.', requestDataMd.source);
381
- // при наличии схемы данных выполняется
382
- // их конвертация и валидация
383
+ // при наличии схемы данных применяются значения
384
+ // по умолчанию, выполняется конвертация входящего
385
+ // значения и валидация согласно схеме
383
386
  if (requestDataMd.schema) {
387
+ data = defaultsApplier.applyDefaultValuesIfNeeded(data, requestDataMd.schema, requestDataMd.source);
388
+ debug('Default values applied.');
384
389
  data = dataTypeCaster.cast(data, requestDataMd.schema, {
385
390
  noTypeCastError: true,
386
391
  sourcePath: requestDataMd.source,
387
392
  });
388
- debug('Data type casting is passed.');
393
+ debug('Data type casting applied.');
389
394
  dataValidator.validate(data, requestDataMd.schema, requestDataMd.source);
390
- debug('Data validation is passed.');
395
+ debug('Data validation passed.');
391
396
  }
392
397
  // если свойство данных не определено,
393
398
  // то используем весь объекта данных
@@ -1,5 +1,4 @@
1
1
  import { expect } from 'chai';
2
- import { describe } from 'mocha';
3
2
  import { Reflector } from '@e22m4u/ts-reflector';
4
3
  import { AfterActionReflector } from './after-action-reflector.js';
5
4
  import { AFTER_ACTION_METADATA_KEY } from './after-action-metadata.js';
@@ -1,5 +1,4 @@
1
1
  import { expect } from 'chai';
2
- import { describe } from 'mocha';
3
2
  import { Reflector } from '@e22m4u/ts-reflector';
4
3
  import { BeforeActionReflector } from './before-action-reflector.js';
5
4
  import { BEFORE_ACTION_METADATA_KEY } from './before-action-metadata.js';
@@ -2,5 +2,6 @@ export * from './rest-action/index.js';
2
2
  export * from './request-data/index.js';
3
3
  export * from './after-action/index.js';
4
4
  export * from './before-action/index.js';
5
+ export * from './response-body/index.js';
5
6
  export * from './rest-controller/index.js';
6
7
  export * from './request-context/index.js';
@@ -2,5 +2,6 @@ export * from './rest-action/index.js';
2
2
  export * from './request-data/index.js';
3
3
  export * from './after-action/index.js';
4
4
  export * from './before-action/index.js';
5
+ export * from './response-body/index.js';
5
6
  export * from './rest-controller/index.js';
6
7
  export * from './request-context/index.js';
@@ -1,5 +1,4 @@
1
1
  import { expect } from 'chai';
2
- import { describe } from 'mocha';
3
2
  import { Reflector } from '@e22m4u/ts-reflector';
4
3
  import { RequestContextReflector } from './request-context-reflector.js';
5
4
  import { REQUEST_CONTEXT_METADATA_KEY } from './request-context-metadata.js';
@@ -11,22 +11,22 @@ export type RequestDataOptions = RequestDataMetadata;
11
11
  *
12
12
  * @param options
13
13
  */
14
- export declare function requestData<T extends object>(options: RequestDataOptions): (target: Prototype<T>, propertyKey: string, indexOrDescriptor: number) => void;
14
+ export declare function requestData<T extends object>(options: RequestDataOptions): (target: Prototype<T>, propertyKey: string, index: number) => void;
15
15
  /**
16
16
  * Decorator aliases.
17
17
  */
18
- export declare const requestParams: () => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
19
- export declare const requestParam: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
20
- export declare const requestQueries: () => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
21
- export declare const requestQuery: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
22
- export declare const requestHeaders: () => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
23
- export declare const requestHeader: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
24
- export declare const requestCookies: () => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
25
- export declare const requestCookie: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
26
- export declare const requestField: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
18
+ export declare const requestParams: () => (target: Prototype<object>, propertyKey: string, index: number) => void;
19
+ export declare const requestParam: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
20
+ export declare const requestQueries: () => (target: Prototype<object>, propertyKey: string, index: number) => void;
21
+ export declare const requestQuery: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
22
+ export declare const requestHeaders: () => (target: Prototype<object>, propertyKey: string, index: number) => void;
23
+ export declare const requestHeader: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
24
+ export declare const requestCookies: () => (target: Prototype<object>, propertyKey: string, index: number) => void;
25
+ export declare const requestCookie: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
26
+ export declare const requestField: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, index: number) => void;
27
27
  /**
28
28
  * Request body decorator.
29
29
  *
30
30
  * @param schemaOrType
31
31
  */
32
- export declare function requestBody(schemaOrType?: DataSchema | DataType): (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
32
+ export declare function requestBody(schemaOrType?: DataSchema | DataType): (target: Prototype<object>, propertyKey: string, index: number) => void;
@@ -9,12 +9,12 @@ import { RequestDataReflector } from './request-data-reflector.js';
9
9
  * @param options
10
10
  */
11
11
  export function requestData(options) {
12
- return function (target, propertyKey, indexOrDescriptor) {
13
- const decoratorType = getDecoratorTargetType(target, propertyKey, indexOrDescriptor);
12
+ return function (target, propertyKey, index) {
13
+ const decoratorType = getDecoratorTargetType(target, propertyKey, index);
14
14
  if (decoratorType !== DecoratorTargetType.INSTANCE_METHOD_PARAMETER)
15
15
  throw new Error('@requestData decorator is only supported ' +
16
16
  'on an instance method parameter.');
17
- RequestDataReflector.setMetadata(options, target.constructor, indexOrDescriptor, propertyKey);
17
+ RequestDataReflector.setMetadata(options, target.constructor, index, propertyKey);
18
18
  };
19
19
  }
20
20
  /**
@@ -1,5 +1,4 @@
1
1
  import { expect } from 'chai';
2
- import { describe } from 'mocha';
3
2
  import { Reflector } from '@e22m4u/ts-reflector';
4
3
  import { RequestDataSource } from './request-data-metadata.js';
5
4
  import { RequestDataReflector } from './request-data-reflector.js';
@@ -0,0 +1,3 @@
1
+ export * from './response-body-metadata.js';
2
+ export * from './response-body-decorator.js';
3
+ export * from './response-body-reflector.js';
@@ -0,0 +1,3 @@
1
+ export * from './response-body-metadata.js';
2
+ export * from './response-body-decorator.js';
3
+ export * from './response-body-reflector.js';
@@ -0,0 +1,9 @@
1
+ import { Prototype } from '../../types.js';
2
+ import { DataType } from '@e22m4u/ts-data-schema';
3
+ import { DataSchema } from '@e22m4u/ts-data-schema';
4
+ /**
5
+ * Response body decorator.
6
+ *
7
+ * @param schemaOrType
8
+ */
9
+ export declare function responseBody<T extends object>(schemaOrType?: DataSchema | DataType): (target: Prototype<T>, propertyKey: string, descriptor: PropertyDescriptor) => void;