@e22m4u/ts-rest-router 0.1.0 → 0.1.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.
- package/README.md +108 -110
- package/dist/cjs/index.cjs +3 -3
- package/dist/esm/decorators/request-data/request-data-decorator.d.ts +1 -1
- package/dist/esm/decorators/request-data/request-data-decorator.js +1 -1
- package/dist/esm/decorators/request-data/request-data-decorator.spec.js +5 -5
- package/package.json +18 -18
- package/src/controller-registry.spec.ts +2 -6
- package/src/decorators/request-data/request-data-decorator.spec.ts +5 -5
- package/src/decorators/request-data/request-data-decorator.ts +1 -1
- package/README-ru.md +0 -268
package/README.md
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
# @e22m4u/ts-rest-router
|
2
2
|
|
3
|
-
|
3
|
+
REST маршрутизатор на основе контроллеров для TypeScript.
|
4
4
|
|
5
|
-
|
5
|
+
#### Основные возможности
|
6
6
|
|
7
|
-
|
7
|
+
- Декларативное определение маршрутов через декораторы.
|
8
|
+
- Типизированные параметры запросов (body, query, params).
|
9
|
+
- Поддержка middleware до и после обработки запроса.
|
10
|
+
- Валидация входящих данных.
|
11
|
+
- Поддержка всех HTTP методов (GET, POST, PUT, DELETE и т.д.).
|
8
12
|
|
9
|
-
|
10
|
-
- Typed request parameters (body, query, params).
|
11
|
-
- Pre and post request middleware support.
|
12
|
-
- Input data validation.
|
13
|
-
- Support for all HTTP methods (GET, POST, PUT, DELETE, etc.).
|
14
|
-
|
15
|
-
## Installation
|
13
|
+
## Установка
|
16
14
|
|
17
15
|
```bash
|
18
16
|
npm install @e22m4u/ts-rest-router
|
19
17
|
```
|
20
18
|
|
21
|
-
####
|
19
|
+
#### Поддержка декораторов
|
22
20
|
|
23
|
-
|
24
|
-
|
21
|
+
Для включения поддержки декораторов, добавьте указанные
|
22
|
+
ниже опции в файл `tsconfig.json` вашего проекта.
|
25
23
|
|
26
24
|
```json
|
27
25
|
{
|
@@ -30,152 +28,152 @@ options to your `tsconfig.json` file.
|
|
30
28
|
}
|
31
29
|
```
|
32
30
|
|
33
|
-
##
|
31
|
+
## Базовое использование
|
34
32
|
|
35
|
-
|
33
|
+
Создание контроллера и методов
|
36
34
|
|
37
35
|
```ts
|
38
36
|
import {get} from '@e22m4u/ts-rest-router';
|
39
37
|
import {post} from '@e22m4u/ts-rest-router';
|
40
|
-
import {
|
38
|
+
import {field} from '@e22m4u/ts-rest-router';
|
41
39
|
import {DataType} from '@e22m4u/ts-rest-router';
|
42
40
|
import {controller} from '@e22m4u/ts-rest-router';
|
43
41
|
|
44
|
-
@controller('/users')
|
45
|
-
class UserController {
|
46
|
-
@post('/login')
|
42
|
+
@controller('/users') // путь контроллера
|
43
|
+
class UserController { // класс контроллера
|
44
|
+
@post('/login') // метод POST /users/login
|
47
45
|
async login(
|
48
|
-
@
|
49
|
-
type: DataType.STRING,
|
50
|
-
required: true,
|
46
|
+
@field('username', { // поле "username" в теле запроса
|
47
|
+
type: DataType.STRING, // тип параметра допускает только строки
|
48
|
+
required: true, // параметр является обязательным
|
51
49
|
})
|
52
50
|
username: string,
|
53
|
-
@
|
54
|
-
type: DataType.STRING,
|
55
|
-
required: true,
|
51
|
+
@field('password', { // поле "password" в теле запроса
|
52
|
+
type: DataType.STRING, // тип параметра допускает только строки
|
53
|
+
required: true, // параметр является обязательным
|
56
54
|
})
|
57
55
|
password: string,
|
58
56
|
) {
|
59
|
-
return {
|
60
|
-
id: '123',
|
61
|
-
firstName: 'John',
|
57
|
+
return { // если метод возвращает объект,
|
58
|
+
id: '123', // то результат будет представлен как
|
59
|
+
firstName: 'John', // "Content-Type: application/json"
|
62
60
|
lastName: 'Doe',
|
63
61
|
};
|
64
62
|
}
|
65
63
|
}
|
66
64
|
```
|
67
65
|
|
68
|
-
|
66
|
+
Регистрация контроллеров и запуск сервера
|
69
67
|
|
70
68
|
```ts
|
71
69
|
import http from 'http';
|
72
70
|
import {RestRouter} from '@e22m4u/ts-rest-router';
|
73
71
|
|
74
|
-
//
|
72
|
+
// создание роутера и регистрация контроллеров
|
75
73
|
const router = new RestRouter();
|
76
74
|
router.registerController(UserController);
|
77
75
|
router.registerController(ProductController);
|
78
76
|
|
79
|
-
//
|
77
|
+
// создание сервера и регистрация обработчика запросов
|
80
78
|
const server = new http.Server();
|
81
79
|
server.on('request', router.requestListener);
|
82
80
|
|
83
|
-
//
|
81
|
+
// запуск сервера
|
84
82
|
server.listen('8080', '0.0.0.0', () => {
|
85
83
|
console.log(`Server is running on http://localhost:8080`);
|
86
84
|
});
|
87
85
|
```
|
88
86
|
|
89
|
-
##
|
87
|
+
## Декораторы
|
90
88
|
|
91
|
-
|
89
|
+
Контроллер и методы:
|
92
90
|
|
93
|
-
- `@controller` -
|
94
|
-
- `@action` -
|
95
|
-
- `@get` - GET
|
96
|
-
- `@post` - POST
|
97
|
-
- `@put` - PUT
|
98
|
-
- `@patch` - PATCH
|
99
|
-
- `@del` - DELETE
|
91
|
+
- `@controller` - определяет класс как контроллер
|
92
|
+
- `@action` - базовый декоратор для методов
|
93
|
+
- `@get` - GET запросы
|
94
|
+
- `@post` - POST запросы
|
95
|
+
- `@put` - PUT запросы
|
96
|
+
- `@patch` - PATCH запросы
|
97
|
+
- `@del` - DELETE запросы
|
100
98
|
|
101
|
-
|
99
|
+
Хуки запроса:
|
102
100
|
|
103
|
-
- `@before` - middleware
|
104
|
-
- `@after` - middleware
|
101
|
+
- `@before` - middleware перед обработкой запроса
|
102
|
+
- `@after` - middleware после обработки запроса
|
105
103
|
|
106
|
-
|
104
|
+
Параметры запроса:
|
107
105
|
|
108
|
-
- `@param` -
|
109
|
-
- `@params` -
|
110
|
-
- `@query` -
|
111
|
-
- `@queries` -
|
112
|
-
- `@body` -
|
113
|
-
- `@
|
114
|
-
- `@header` -
|
115
|
-
- `@headers` -
|
116
|
-
- `@cookie` -
|
117
|
-
- `@cookies` -
|
118
|
-
- `@requestContext` -
|
119
|
-
- `@requestData` -
|
106
|
+
- `@param` - один параметр URL
|
107
|
+
- `@params` - все параметры URL как объект
|
108
|
+
- `@query` - один query параметр
|
109
|
+
- `@queries` - все query параметры как объект
|
110
|
+
- `@body` - тело запроса
|
111
|
+
- `@field` - поле в теле запроса
|
112
|
+
- `@header` - один заголовок
|
113
|
+
- `@headers` - все заголовки как объект
|
114
|
+
- `@cookie` - одна cookie
|
115
|
+
- `@cookies` - все cookies как объект
|
116
|
+
- `@requestContext` - доступ к контексту запроса
|
117
|
+
- `@requestData` - универсальный декоратор для доступа к данным запроса
|
120
118
|
|
121
119
|
#### `@controller(options?: ControllerOptions)`
|
122
120
|
|
123
|
-
|
121
|
+
Определение контроллера.
|
124
122
|
|
125
123
|
```ts
|
126
124
|
@controller()
|
127
125
|
class UserController {
|
128
|
-
//
|
126
|
+
// методы контроллера
|
129
127
|
}
|
130
128
|
```
|
131
129
|
|
132
|
-
|
130
|
+
Определение пути контроллера.
|
133
131
|
|
134
132
|
```ts
|
135
|
-
@controller('/users') //
|
133
|
+
@controller('/users') // путь контроллера
|
136
134
|
class UserController {
|
137
|
-
//
|
135
|
+
// методы контроллера
|
138
136
|
}
|
139
137
|
```
|
140
138
|
|
141
|
-
|
139
|
+
Дополнительные параметры декоратора.
|
142
140
|
|
143
141
|
```ts
|
144
142
|
@controller({
|
145
|
-
path: '/api', //
|
146
|
-
before: [authMiddleware], // middleware
|
147
|
-
after: [loggerMiddleware], // middleware
|
143
|
+
path: '/api', // путь контроллера
|
144
|
+
before: [authMiddleware], // middleware до обработки запроса
|
145
|
+
after: [loggerMiddleware], // middleware после обработки запроса
|
148
146
|
})
|
149
147
|
class UserController {
|
150
|
-
//
|
148
|
+
// методы контроллера
|
151
149
|
}
|
152
150
|
```
|
153
151
|
|
154
152
|
#### `@get(path: string, options?: ActionOptions)`
|
155
153
|
|
156
|
-
|
154
|
+
Определение метода GET.
|
157
155
|
|
158
156
|
```ts
|
159
|
-
@controller('/users') //
|
160
|
-
class UserController { //
|
161
|
-
@get('/whoAmI') // GET /users/whoAmI
|
157
|
+
@controller('/users') // путь контроллера
|
158
|
+
class UserController { // класс контроллера
|
159
|
+
@get('/whoAmI') // маршрут GET /users/whoAmI
|
162
160
|
async whoAmI() {
|
163
|
-
return { //
|
164
|
-
name: 'John', //
|
165
|
-
surname: 'Doe', //
|
161
|
+
return { // если метод возвращает объект,
|
162
|
+
name: 'John', // то результат будет представлен
|
163
|
+
surname: 'Doe', // как "Content-Type: application/json"
|
166
164
|
};
|
167
165
|
}
|
168
166
|
}
|
169
167
|
```
|
170
168
|
|
171
|
-
|
169
|
+
Дополнительные параметры декоратора.
|
172
170
|
|
173
171
|
```ts
|
174
|
-
@controller('/users') //
|
175
|
-
class UserController { //
|
176
|
-
@get('/whoAmI', { // GET /users/whoAmI
|
177
|
-
before: [authMiddleware], // middleware
|
178
|
-
after: [loggerMiddleware], // middleware
|
172
|
+
@controller('/users') // путь контроллера
|
173
|
+
class UserController { // класс контроллера
|
174
|
+
@get('/whoAmI', { // маршрут GET /users/whoAmI
|
175
|
+
before: [authMiddleware], // middleware до обработки запроса
|
176
|
+
after: [loggerMiddleware], // middleware после обработки запроса
|
179
177
|
})
|
180
178
|
async whoAmI() {
|
181
179
|
return {
|
@@ -188,17 +186,17 @@ class UserController { // controller class
|
|
188
186
|
|
189
187
|
#### `@requestContext(propertyName?: string)`
|
190
188
|
|
191
|
-
|
189
|
+
Доступ к контексту запроса.
|
192
190
|
|
193
191
|
```ts
|
194
192
|
import {RequestContext} from '@e22m4u/js-trie-router';
|
195
193
|
|
196
|
-
@controller('/users') //
|
197
|
-
class UserController { //
|
198
|
-
@get('/:id') // GET /users/:id
|
194
|
+
@controller('/users') // путь контроллера
|
195
|
+
class UserController { // класс контроллера
|
196
|
+
@get('/:id') // маршрут GET /users/:id
|
199
197
|
findById(
|
200
|
-
@requestContext() //
|
201
|
-
ctx: RequestContext, //
|
198
|
+
@requestContext() // включениее контекста запроса
|
199
|
+
ctx: RequestContext, // в качестве параметра метода
|
202
200
|
) {
|
203
201
|
console.log(ctx.req); // IncomingMessage
|
204
202
|
console.log(ctx.res); // ServerResponse
|
@@ -214,20 +212,20 @@ class UserController { // controller class
|
|
214
212
|
}
|
215
213
|
```
|
216
214
|
|
217
|
-
|
215
|
+
Доступ к свойствам контекста.
|
218
216
|
|
219
217
|
```ts
|
220
218
|
import {ServerResponse} from 'http';
|
221
219
|
import {IncomingMessage} from 'http';
|
222
220
|
|
223
|
-
@controller('/users') //
|
224
|
-
class UserController { //
|
225
|
-
@get('/:id') // GET /users/:id
|
221
|
+
@controller('/users') // путь контроллера
|
222
|
+
class UserController { // класс контроллера
|
223
|
+
@get('/:id') // маршрут GET /users/:id
|
226
224
|
findById(
|
227
|
-
@requestContext('req') //
|
228
|
-
req: IncomingMessage, //
|
229
|
-
@requestContext('res') //
|
230
|
-
res: ServerResponse, //
|
225
|
+
@requestContext('req') // декоратор контекста запроса
|
226
|
+
req: IncomingMessage, // включающий свойство "req"
|
227
|
+
@requestContext('res') // декоратор контекста запроса
|
228
|
+
res: ServerResponse, // включающий свойство "res"
|
231
229
|
) {
|
232
230
|
console.log(req); // IncomingMessage
|
233
231
|
console.log(res); // ServerResponse
|
@@ -235,34 +233,34 @@ class UserController { // controller class
|
|
235
233
|
}
|
236
234
|
```
|
237
235
|
|
238
|
-
|
236
|
+
Свойства контекста:
|
239
237
|
|
240
|
-
- `container: ServiceContainer`
|
241
|
-
- `req: IncomingMessage`
|
242
|
-
- `res: ServerResponse`
|
243
|
-
- `params: ParsedParams`
|
244
|
-
- `query: ParsedQuery`
|
245
|
-
- `headers: ParsedHeaders`
|
246
|
-
- `cookie: ParsedCookie`
|
247
|
-
- `method: string`
|
248
|
-
- `path: string`
|
249
|
-
- `pathname: string`
|
250
|
-
- `body: unknown`
|
238
|
+
- `container: ServiceContainer` экземпляр [сервис-контейнера](https://npmjs.com/package/@e22m4u/js-service)
|
239
|
+
- `req: IncomingMessage` нативный поток входящего запроса
|
240
|
+
- `res: ServerResponse` нативный поток ответа сервера
|
241
|
+
- `params: ParsedParams` объект ключ-значение с параметрами пути
|
242
|
+
- `query: ParsedQuery` объект ключ-значение с параметрами строки запроса
|
243
|
+
- `headers: ParsedHeaders` объект ключ-значение с заголовками запроса
|
244
|
+
- `cookie: ParsedCookie` объект ключ-значение разобранного заголовка `cookie`
|
245
|
+
- `method: string` метод запроса в верхнем регистре, например `GET`, `POST` и т.д.
|
246
|
+
- `path: string` путь включающий строку запроса, например `/myPath?foo=bar`
|
247
|
+
- `pathname: string` путь запроса, например `/myMath`
|
248
|
+
- `body: unknown` тело запроса
|
251
249
|
|
252
|
-
##
|
250
|
+
## Отладка
|
253
251
|
|
254
|
-
|
252
|
+
Установка переменной `DEBUG` включает вывод логов.
|
255
253
|
|
256
254
|
```bash
|
257
255
|
DEBUG=tsRestRouter* npm run test
|
258
256
|
```
|
259
257
|
|
260
|
-
##
|
258
|
+
## Тесты
|
261
259
|
|
262
260
|
```bash
|
263
261
|
npm run test
|
264
262
|
```
|
265
263
|
|
266
|
-
##
|
264
|
+
## Лицензия
|
267
265
|
|
268
266
|
MIT
|
package/dist/cjs/index.cjs
CHANGED
@@ -51,7 +51,6 @@ __export(index_exports, {
|
|
51
51
|
after: () => after,
|
52
52
|
before: () => before,
|
53
53
|
body: () => body,
|
54
|
-
bodyProp: () => bodyProp,
|
55
54
|
capitalize: () => capitalize,
|
56
55
|
controller: () => controller,
|
57
56
|
cookie: () => cookie,
|
@@ -59,6 +58,7 @@ __export(index_exports, {
|
|
59
58
|
createDebugger: () => createDebugger,
|
60
59
|
createError: () => createError,
|
61
60
|
del: () => del,
|
61
|
+
field: () => field,
|
62
62
|
get: () => get,
|
63
63
|
header: () => header,
|
64
64
|
headers: () => headers,
|
@@ -470,7 +470,7 @@ var headers = createRequestDataDecoratorWithSource(RequestDataSource.HEADERS);
|
|
470
470
|
var header = createRequestDataPropertyDecoratorWithSource(RequestDataSource.HEADERS);
|
471
471
|
var cookies = createRequestDataDecoratorWithSource(RequestDataSource.COOKIE);
|
472
472
|
var cookie = createRequestDataPropertyDecoratorWithSource(RequestDataSource.COOKIE);
|
473
|
-
var
|
473
|
+
var field = createRequestDataPropertyDecoratorWithSource(RequestDataSource.BODY);
|
474
474
|
function body(schemaOrType) {
|
475
475
|
let schema;
|
476
476
|
if (typeof schemaOrType === "object") {
|
@@ -959,7 +959,6 @@ var RestRouter = _RestRouter;
|
|
959
959
|
after,
|
960
960
|
before,
|
961
961
|
body,
|
962
|
-
bodyProp,
|
963
962
|
capitalize,
|
964
963
|
controller,
|
965
964
|
cookie,
|
@@ -967,6 +966,7 @@ var RestRouter = _RestRouter;
|
|
967
966
|
createDebugger,
|
968
967
|
createError,
|
969
968
|
del,
|
969
|
+
field,
|
970
970
|
get,
|
971
971
|
header,
|
972
972
|
headers,
|
@@ -23,7 +23,7 @@ export declare const headers: () => (target: Prototype<object>, propertyKey: str
|
|
23
23
|
export declare const header: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
|
24
24
|
export declare const cookies: () => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
|
25
25
|
export declare const cookie: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
|
26
|
-
export declare const
|
26
|
+
export declare const field: (propertyKey: string, schemaOrType?: DataSchema | DataType) => (target: Prototype<object>, propertyKey: string, indexOrDescriptor: number) => void;
|
27
27
|
/**
|
28
28
|
* Request body decorator.
|
29
29
|
*
|
@@ -63,7 +63,7 @@ export const headers = createRequestDataDecoratorWithSource(RequestDataSource.HE
|
|
63
63
|
export const header = createRequestDataPropertyDecoratorWithSource(RequestDataSource.HEADERS);
|
64
64
|
export const cookies = createRequestDataDecoratorWithSource(RequestDataSource.COOKIE);
|
65
65
|
export const cookie = createRequestDataPropertyDecoratorWithSource(RequestDataSource.COOKIE);
|
66
|
-
export const
|
66
|
+
export const field = createRequestDataPropertyDecoratorWithSource(RequestDataSource.BODY);
|
67
67
|
/**
|
68
68
|
* Request body decorator.
|
69
69
|
*
|
@@ -16,13 +16,13 @@ import { DataType } from '@e22m4u/ts-data-schema';
|
|
16
16
|
import { body } from './request-data-decorator.js';
|
17
17
|
import { param } from './request-data-decorator.js';
|
18
18
|
import { query } from './request-data-decorator.js';
|
19
|
+
import { field } from './request-data-decorator.js';
|
19
20
|
import { cookie } from './request-data-decorator.js';
|
20
21
|
import { header } from './request-data-decorator.js';
|
21
22
|
import { params } from './request-data-decorator.js';
|
22
23
|
import { queries } from './request-data-decorator.js';
|
23
24
|
import { cookies } from './request-data-decorator.js';
|
24
25
|
import { headers } from './request-data-decorator.js';
|
25
|
-
import { bodyProp } from './request-data-decorator.js';
|
26
26
|
import { requestData } from './request-data-decorator.js';
|
27
27
|
import { RequestDataSource } from './request-data-metadata.js';
|
28
28
|
import { RequestDataReflector } from './request-data-reflector.js';
|
@@ -460,13 +460,13 @@ describe('requestData', function () {
|
|
460
460
|
});
|
461
461
|
});
|
462
462
|
});
|
463
|
-
describe('
|
463
|
+
describe('field', function () {
|
464
464
|
it('sets a given "propertyKey" to the target metadata', function () {
|
465
465
|
class Target {
|
466
466
|
myMethod(prop) { }
|
467
467
|
}
|
468
468
|
__decorate([
|
469
|
-
__param(0,
|
469
|
+
__param(0, field('myPropertyKey')),
|
470
470
|
__metadata("design:type", Function),
|
471
471
|
__metadata("design:paramtypes", [Object]),
|
472
472
|
__metadata("design:returntype", void 0)
|
@@ -485,7 +485,7 @@ describe('requestData', function () {
|
|
485
485
|
myMethod(prop) { }
|
486
486
|
}
|
487
487
|
__decorate([
|
488
|
-
__param(0,
|
488
|
+
__param(0, field(propertyKey, propertyType)),
|
489
489
|
__metadata("design:type", Function),
|
490
490
|
__metadata("design:paramtypes", [Object]),
|
491
491
|
__metadata("design:returntype", void 0)
|
@@ -514,7 +514,7 @@ describe('requestData', function () {
|
|
514
514
|
myMethod(prop) { }
|
515
515
|
}
|
516
516
|
__decorate([
|
517
|
-
__param(0,
|
517
|
+
__param(0, field(propertyKey, schema)),
|
518
518
|
__metadata("design:type", Function),
|
519
519
|
__metadata("design:paramtypes", [Object]),
|
520
520
|
__metadata("design:returntype", void 0)
|
package/package.json
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
{
|
2
2
|
"name": "@e22m4u/ts-rest-router",
|
3
|
-
"version": "0.1.
|
4
|
-
"description": "
|
3
|
+
"version": "0.1.2",
|
4
|
+
"description": "REST маршрутизатор на основе контроллеров для TypeScript",
|
5
5
|
"author": "e22m4u <e22m4u@yandex.ru>",
|
6
|
+
"license": "MIT",
|
6
7
|
"keywords": [
|
7
8
|
"rest",
|
8
9
|
"http",
|
@@ -49,28 +50,27 @@
|
|
49
50
|
"http-errors": "~2.0.0"
|
50
51
|
},
|
51
52
|
"devDependencies": {
|
52
|
-
"@commitlint/cli": "~19.
|
53
|
-
"@commitlint/config-conventional": "~19.
|
54
|
-
"@eslint/js": "~9.
|
55
|
-
"@types/chai": "~5.
|
53
|
+
"@commitlint/cli": "~19.8.0",
|
54
|
+
"@commitlint/config-conventional": "~19.8.0",
|
55
|
+
"@eslint/js": "~9.25.1",
|
56
|
+
"@types/chai": "~5.2.1",
|
56
57
|
"@types/debug": "~4.1.12",
|
57
58
|
"@types/http-errors": "~2.0.4",
|
58
59
|
"@types/mocha": "~10.0.10",
|
59
|
-
"@types/node": "~22.
|
60
|
+
"@types/node": "~22.14.1",
|
60
61
|
"c8": "~10.1.3",
|
61
|
-
"chai": "~5.
|
62
|
-
"esbuild": "~0.
|
63
|
-
"eslint": "~9.
|
64
|
-
"eslint-config-prettier": "~
|
62
|
+
"chai": "~5.2.0",
|
63
|
+
"esbuild": "~0.25.3",
|
64
|
+
"eslint": "~9.25.1",
|
65
|
+
"eslint-config-prettier": "~10.1.2",
|
65
66
|
"eslint-plugin-chai-expect": "~3.1.0",
|
66
67
|
"eslint-plugin-mocha": "~10.5.0",
|
67
68
|
"husky": "~9.1.7",
|
68
|
-
"mocha": "~11.0
|
69
|
-
"prettier": "~3.
|
69
|
+
"mocha": "~11.1.0",
|
70
|
+
"prettier": "~3.5.3",
|
70
71
|
"rimraf": "~6.0.1",
|
71
|
-
"tsx": "~4.19.
|
72
|
-
"typescript": "~5.
|
73
|
-
"typescript-eslint": "~8.
|
74
|
-
}
|
75
|
-
"license": "MIT"
|
72
|
+
"tsx": "~4.19.3",
|
73
|
+
"typescript": "~5.8.3",
|
74
|
+
"typescript-eslint": "~8.31.0"
|
75
|
+
}
|
76
76
|
}
|
@@ -6,6 +6,7 @@ import {body} from './decorators/index.js';
|
|
6
6
|
import {after} from './decorators/index.js';
|
7
7
|
import {query} from './decorators/index.js';
|
8
8
|
import {param} from './decorators/index.js';
|
9
|
+
import {field} from './decorators/index.js';
|
9
10
|
import {cookie} from './decorators/index.js';
|
10
11
|
import {params} from './decorators/index.js';
|
11
12
|
import {before} from './decorators/index.js';
|
@@ -13,7 +14,6 @@ import {header} from './decorators/index.js';
|
|
13
14
|
import {cookies} from './decorators/index.js';
|
14
15
|
import {queries} from './decorators/index.js';
|
15
16
|
import {headers} from './decorators/index.js';
|
16
|
-
import {bodyProp} from './decorators/index.js';
|
17
17
|
import {HookName} from '@e22m4u/js-trie-router';
|
18
18
|
import {controller} from './decorators/index.js';
|
19
19
|
import {TrieRouter} from '@e22m4u/js-trie-router';
|
@@ -31,13 +31,9 @@ import {ControllerRegistry} from './controller-registry.js';
|
|
31
31
|
|
32
32
|
const PRE_HANDLER_1 = () => undefined;
|
33
33
|
const PRE_HANDLER_2 = () => undefined;
|
34
|
-
// const PRE_HANDLER_3 = () => undefined;
|
35
|
-
// const PRE_HANDLER_4 = () => undefined;
|
36
34
|
|
37
35
|
const POST_HANDLER_1 = () => undefined;
|
38
36
|
const POST_HANDLER_2 = () => undefined;
|
39
|
-
// const POST_HANDLER_3 = () => undefined;
|
40
|
-
// const POST_HANDLER_4 = () => undefined;
|
41
37
|
|
42
38
|
describe('ControllerRegistry', function () {
|
43
39
|
it('has a public property with set of controllers', function () {
|
@@ -872,7 +868,7 @@ describe('ControllerRegistry', function () {
|
|
872
868
|
class MyController {
|
873
869
|
@post('/myAction')
|
874
870
|
myAction(
|
875
|
-
@
|
871
|
+
@field('foo')
|
876
872
|
foo: object,
|
877
873
|
) {
|
878
874
|
expect(foo).to.be.eq('bar');
|
@@ -4,13 +4,13 @@ import {DataType} from '@e22m4u/ts-data-schema';
|
|
4
4
|
import {body} from './request-data-decorator.js';
|
5
5
|
import {param} from './request-data-decorator.js';
|
6
6
|
import {query} from './request-data-decorator.js';
|
7
|
+
import {field} from './request-data-decorator.js';
|
7
8
|
import {cookie} from './request-data-decorator.js';
|
8
9
|
import {header} from './request-data-decorator.js';
|
9
10
|
import {params} from './request-data-decorator.js';
|
10
11
|
import {queries} from './request-data-decorator.js';
|
11
12
|
import {cookies} from './request-data-decorator.js';
|
12
13
|
import {headers} from './request-data-decorator.js';
|
13
|
-
import {bodyProp} from './request-data-decorator.js';
|
14
14
|
import {requestData} from './request-data-decorator.js';
|
15
15
|
import {RequestDataSource} from './request-data-metadata.js';
|
16
16
|
import {RequestDataReflector} from './request-data-reflector.js';
|
@@ -409,11 +409,11 @@ describe('requestData', function () {
|
|
409
409
|
});
|
410
410
|
});
|
411
411
|
|
412
|
-
describe('
|
412
|
+
describe('field', function () {
|
413
413
|
it('sets a given "propertyKey" to the target metadata', function () {
|
414
414
|
class Target {
|
415
415
|
myMethod(
|
416
|
-
@
|
416
|
+
@field('myPropertyKey')
|
417
417
|
prop: unknown,
|
418
418
|
) {}
|
419
419
|
}
|
@@ -430,7 +430,7 @@ describe('requestData', function () {
|
|
430
430
|
const propertyType = DataType.STRING;
|
431
431
|
class Target {
|
432
432
|
myMethod(
|
433
|
-
@
|
433
|
+
@field(propertyKey, propertyType)
|
434
434
|
prop: unknown,
|
435
435
|
) {}
|
436
436
|
}
|
@@ -457,7 +457,7 @@ describe('requestData', function () {
|
|
457
457
|
const propertyKey = 'myPropertyKey';
|
458
458
|
class Target {
|
459
459
|
myMethod(
|
460
|
-
@
|
460
|
+
@field(propertyKey, schema)
|
461
461
|
prop: unknown,
|
462
462
|
) {}
|
463
463
|
}
|
@@ -109,7 +109,7 @@ export const cookies = createRequestDataDecoratorWithSource(
|
|
109
109
|
export const cookie = createRequestDataPropertyDecoratorWithSource(
|
110
110
|
RequestDataSource.COOKIE,
|
111
111
|
);
|
112
|
-
export const
|
112
|
+
export const field = createRequestDataPropertyDecoratorWithSource(
|
113
113
|
RequestDataSource.BODY,
|
114
114
|
);
|
115
115
|
|
package/README-ru.md
DELETED
@@ -1,268 +0,0 @@
|
|
1
|
-
# @e22m4u/ts-rest-router
|
2
|
-
|
3
|
-
*[English](./README.md) | Русский*
|
4
|
-
|
5
|
-
Реализация REST маршрутизатора на основе контроллеров для TypeScript.
|
6
|
-
|
7
|
-
#### Основные возможности
|
8
|
-
|
9
|
-
- Декларативное определение маршрутов через декораторы.
|
10
|
-
- Типизированные параметры запросов (body, query, params).
|
11
|
-
- Поддержка middleware до и после обработки запроса.
|
12
|
-
- Валидация входящих данных.
|
13
|
-
- Поддержка всех HTTP методов (GET, POST, PUT, DELETE и т.д.).
|
14
|
-
|
15
|
-
## Установка
|
16
|
-
|
17
|
-
```bash
|
18
|
-
npm install @e22m4u/ts-rest-router
|
19
|
-
```
|
20
|
-
|
21
|
-
#### Поддержка декораторов
|
22
|
-
|
23
|
-
Для включения поддержки декораторов, добавьте указанные
|
24
|
-
ниже опции в файл `tsconfig.json` вашего проекта.
|
25
|
-
|
26
|
-
```json
|
27
|
-
{
|
28
|
-
"emitDecoratorMetadata": true,
|
29
|
-
"experimentalDecorators": true
|
30
|
-
}
|
31
|
-
```
|
32
|
-
|
33
|
-
## Базовое использование
|
34
|
-
|
35
|
-
Создание контроллера и методов
|
36
|
-
|
37
|
-
```ts
|
38
|
-
import {get} from '@e22m4u/ts-rest-router';
|
39
|
-
import {post} from '@e22m4u/ts-rest-router';
|
40
|
-
import {bodyProp} from '@e22m4u/ts-rest-router';
|
41
|
-
import {DataType} from '@e22m4u/ts-rest-router';
|
42
|
-
import {controller} from '@e22m4u/ts-rest-router';
|
43
|
-
|
44
|
-
@controller('/users') // путь контроллера
|
45
|
-
class UserController { // класс контроллера
|
46
|
-
@post('/login') // метод POST /users/login
|
47
|
-
async login(
|
48
|
-
@bodyProp('username', { // свойство тела запроса "username"
|
49
|
-
type: DataType.STRING, // тип параметра допускает только строки
|
50
|
-
required: true, // параметр является обязательным
|
51
|
-
})
|
52
|
-
username: string,
|
53
|
-
@bodyProp('password', { // свойство тела запроса "password"
|
54
|
-
type: DataType.STRING, // тип параметра допускает только строки
|
55
|
-
required: true, // параметр является обязательным
|
56
|
-
})
|
57
|
-
password: string,
|
58
|
-
) {
|
59
|
-
return { // если метод возвращает объект,
|
60
|
-
id: '123', // то результат будет представлен как
|
61
|
-
firstName: 'John', // "Content-Type: application/json"
|
62
|
-
lastName: 'Doe',
|
63
|
-
};
|
64
|
-
}
|
65
|
-
}
|
66
|
-
```
|
67
|
-
|
68
|
-
Регистрация контроллеров и запуск сервера
|
69
|
-
|
70
|
-
```ts
|
71
|
-
import http from 'http';
|
72
|
-
import {RestRouter} from '@e22m4u/ts-rest-router';
|
73
|
-
|
74
|
-
// создание роутера и регистрация контроллеров
|
75
|
-
const router = new RestRouter();
|
76
|
-
router.registerController(UserController);
|
77
|
-
router.registerController(ProductController);
|
78
|
-
|
79
|
-
// создание сервера и регистрация обработчика запросов
|
80
|
-
const server = new http.Server();
|
81
|
-
server.on('request', router.requestListener);
|
82
|
-
|
83
|
-
// запуск сервера
|
84
|
-
server.listen('8080', '0.0.0.0', () => {
|
85
|
-
console.log(`Server is running on http://localhost:8080`);
|
86
|
-
});
|
87
|
-
```
|
88
|
-
|
89
|
-
## Декораторы
|
90
|
-
|
91
|
-
Контроллер и методы:
|
92
|
-
|
93
|
-
- `@controller` - определяет класс как контроллер
|
94
|
-
- `@action` - базовый декоратор для методов
|
95
|
-
- `@get` - GET запросы
|
96
|
-
- `@post` - POST запросы
|
97
|
-
- `@put` - PUT запросы
|
98
|
-
- `@patch` - PATCH запросы
|
99
|
-
- `@del` - DELETE запросы
|
100
|
-
|
101
|
-
Хуки запроса:
|
102
|
-
|
103
|
-
- `@before` - middleware перед обработкой запроса
|
104
|
-
- `@after` - middleware после обработки запроса
|
105
|
-
|
106
|
-
Параметры запроса:
|
107
|
-
|
108
|
-
- `@param` - один параметр URL
|
109
|
-
- `@params` - все параметры URL как объект
|
110
|
-
- `@query` - один query параметр
|
111
|
-
- `@queries` - все query параметры как объект
|
112
|
-
- `@body` - тело запроса
|
113
|
-
- `@bodyProp` - свойство из тела запроса
|
114
|
-
- `@header` - один заголовок
|
115
|
-
- `@headers` - все заголовки как объект
|
116
|
-
- `@cookie` - одна cookie
|
117
|
-
- `@cookies` - все cookies как объект
|
118
|
-
- `@requestContext` - доступ к контексту запроса
|
119
|
-
- `@requestData` - универсальный декоратор для доступа к данным запроса
|
120
|
-
|
121
|
-
#### `@controller(options?: ControllerOptions)`
|
122
|
-
|
123
|
-
Определение контроллера.
|
124
|
-
|
125
|
-
```ts
|
126
|
-
@controller()
|
127
|
-
class UserController {
|
128
|
-
// методы контроллера
|
129
|
-
}
|
130
|
-
```
|
131
|
-
|
132
|
-
Определение пути контроллера.
|
133
|
-
|
134
|
-
```ts
|
135
|
-
@controller('/users') // путь контроллера
|
136
|
-
class UserController {
|
137
|
-
// методы контроллера
|
138
|
-
}
|
139
|
-
```
|
140
|
-
|
141
|
-
Дополнительные параметры декоратора.
|
142
|
-
|
143
|
-
```ts
|
144
|
-
@controller({
|
145
|
-
path: '/api', // путь контроллера
|
146
|
-
before: [authMiddleware], // middleware до обработки запроса
|
147
|
-
after: [loggerMiddleware], // middleware после обработки запроса
|
148
|
-
})
|
149
|
-
class UserController {
|
150
|
-
// методы контроллера
|
151
|
-
}
|
152
|
-
```
|
153
|
-
|
154
|
-
#### `@get(path: string, options?: ActionOptions)`
|
155
|
-
|
156
|
-
Определение метода GET.
|
157
|
-
|
158
|
-
```ts
|
159
|
-
@controller('/users') // путь контроллера
|
160
|
-
class UserController { // класс контроллера
|
161
|
-
@get('/whoAmI') // маршрут GET /users/whoAmI
|
162
|
-
async whoAmI() {
|
163
|
-
return { // если метод возвращает объект,
|
164
|
-
name: 'John', // то результат будет представлен
|
165
|
-
surname: 'Doe', // как "Content-Type: application/json"
|
166
|
-
};
|
167
|
-
}
|
168
|
-
}
|
169
|
-
```
|
170
|
-
|
171
|
-
Дополнительные параметры декоратора.
|
172
|
-
|
173
|
-
```ts
|
174
|
-
@controller('/users') // путь контроллера
|
175
|
-
class UserController { // класс контроллера
|
176
|
-
@get('/whoAmI', { // маршрут GET /users/whoAmI
|
177
|
-
before: [authMiddleware], // middleware до обработки запроса
|
178
|
-
after: [loggerMiddleware], // middleware после обработки запроса
|
179
|
-
})
|
180
|
-
async whoAmI() {
|
181
|
-
return {
|
182
|
-
name: 'John',
|
183
|
-
surname: 'Doe',
|
184
|
-
};
|
185
|
-
}
|
186
|
-
}
|
187
|
-
```
|
188
|
-
|
189
|
-
#### `@requestContext(propertyName?: string)`
|
190
|
-
|
191
|
-
Доступ к контексту запроса.
|
192
|
-
|
193
|
-
```ts
|
194
|
-
import {RequestContext} from '@e22m4u/js-trie-router';
|
195
|
-
|
196
|
-
@controller('/users') // путь контроллера
|
197
|
-
class UserController { // класс контроллера
|
198
|
-
@get('/:id') // маршрут GET /users/:id
|
199
|
-
findById(
|
200
|
-
@requestContext() // включениее контекста запроса
|
201
|
-
ctx: RequestContext, // в качестве параметра метода
|
202
|
-
) {
|
203
|
-
console.log(ctx.req); // IncomingMessage
|
204
|
-
console.log(ctx.res); // ServerResponse
|
205
|
-
console.log(ctx.params); // {id: 10}
|
206
|
-
console.log(ctx.query); // {include: 'city'}
|
207
|
-
console.log(ctx.headers); // {cookie: 'foo=bar; baz=qux;'}
|
208
|
-
console.log(ctx.cookie); // {foo: 'bar', baz: 'qux'}
|
209
|
-
console.log(ctx.method); // "GET"
|
210
|
-
console.log(ctx.path); // "/users/10?include=city"
|
211
|
-
console.log(ctx.pathname); // "/users/10"
|
212
|
-
// ...
|
213
|
-
}
|
214
|
-
}
|
215
|
-
```
|
216
|
-
|
217
|
-
Доступ к свойствам контекста.
|
218
|
-
|
219
|
-
```ts
|
220
|
-
import {ServerResponse} from 'http';
|
221
|
-
import {IncomingMessage} from 'http';
|
222
|
-
|
223
|
-
@controller('/users') // путь контроллера
|
224
|
-
class UserController { // класс контроллера
|
225
|
-
@get('/:id') // маршрут GET /users/:id
|
226
|
-
findById(
|
227
|
-
@requestContext('req') // декоратор контекста запроса
|
228
|
-
req: IncomingMessage, // включающий свойство "req"
|
229
|
-
@requestContext('res') // декоратор контекста запроса
|
230
|
-
res: ServerResponse, // включающий свойство "res"
|
231
|
-
) {
|
232
|
-
console.log(req); // IncomingMessage
|
233
|
-
console.log(res); // ServerResponse
|
234
|
-
}
|
235
|
-
}
|
236
|
-
```
|
237
|
-
|
238
|
-
Свойства контекста:
|
239
|
-
|
240
|
-
- `container: ServiceContainer` экземпляр [сервис-контейнера](https://npmjs.com/package/@e22m4u/js-service)
|
241
|
-
- `req: IncomingMessage` нативный поток входящего запроса
|
242
|
-
- `res: ServerResponse` нативный поток ответа сервера
|
243
|
-
- `params: ParsedParams` объект ключ-значение с параметрами пути
|
244
|
-
- `query: ParsedQuery` объект ключ-значение с параметрами строки запроса
|
245
|
-
- `headers: ParsedHeaders` объект ключ-значение с заголовками запроса
|
246
|
-
- `cookie: ParsedCookie` объект ключ-значение разобранного заголовка `cookie`
|
247
|
-
- `method: string` метод запроса в верхнем регистре, например `GET`, `POST` и т.д.
|
248
|
-
- `path: string` путь включающий строку запроса, например `/myPath?foo=bar`
|
249
|
-
- `pathname: string` путь запроса, например `/myMath`
|
250
|
-
- `body: unknown` тело запроса
|
251
|
-
|
252
|
-
## Отладка
|
253
|
-
|
254
|
-
Установка переменной `DEBUG` включает вывод логов.
|
255
|
-
|
256
|
-
```bash
|
257
|
-
DEBUG=tsRestRouter* npm run test
|
258
|
-
```
|
259
|
-
|
260
|
-
## Тесты
|
261
|
-
|
262
|
-
```bash
|
263
|
-
npm run test
|
264
|
-
```
|
265
|
-
|
266
|
-
## Лицензия
|
267
|
-
|
268
|
-
MIT
|