@e22m4u/ts-rest-router 0.1.1 → 0.2.0
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 +118 -118
- package/dist/cjs/index.cjs +346 -360
- package/dist/esm/controller-registry.js +28 -28
- package/dist/esm/debuggable-service.d.ts +10 -1
- package/dist/esm/debuggable-service.js +14 -3
- package/dist/esm/decorators/after-action/after-action-decorator.d.ts +9 -0
- package/dist/esm/decorators/{after/after-decorator.js → after-action/after-action-decorator.js} +7 -7
- package/dist/esm/decorators/{before/before-decorator.spec.js → after-action/after-action-decorator.spec.js} +19 -19
- package/dist/esm/decorators/{after/after-metadata.d.ts → after-action/after-action-metadata.d.ts} +4 -4
- package/dist/esm/decorators/after-action/after-action-metadata.js +5 -0
- package/dist/esm/decorators/{after/after-reflector.d.ts → after-action/after-action-reflector.d.ts} +5 -5
- package/dist/esm/decorators/{before/before-reflector.js → after-action/after-action-reflector.js} +6 -6
- package/dist/esm/decorators/{before/before-reflector.spec.js → after-action/after-action-reflector.spec.js} +23 -23
- package/dist/esm/decorators/after-action/index.d.ts +3 -0
- package/dist/esm/decorators/after-action/index.js +3 -0
- package/dist/esm/decorators/before-action/before-action-decorator.d.ts +9 -0
- package/dist/esm/decorators/{before/before-decorator.js → before-action/before-action-decorator.js} +7 -7
- package/dist/esm/decorators/{after/after-decorator.spec.js → before-action/before-action-decorator.spec.js} +19 -19
- package/dist/esm/decorators/{before/before-metadata.d.ts → before-action/before-action-metadata.d.ts} +4 -4
- package/dist/esm/decorators/before-action/before-action-metadata.js +5 -0
- package/dist/esm/decorators/{before/before-reflector.d.ts → before-action/before-action-reflector.d.ts} +5 -5
- package/dist/esm/decorators/{after/after-reflector.js → before-action/before-action-reflector.js} +6 -6
- package/dist/esm/decorators/{after/after-reflector.spec.js → before-action/before-action-reflector.spec.js} +23 -23
- package/dist/esm/decorators/before-action/index.d.ts +3 -0
- package/dist/esm/decorators/before-action/index.js +3 -0
- package/dist/esm/decorators/index.d.ts +4 -4
- package/dist/esm/decorators/index.js +4 -4
- package/dist/esm/decorators/request-context/request-context-decorator.d.ts +4 -4
- package/dist/esm/decorators/request-context/request-context-decorator.js +4 -4
- package/dist/esm/decorators/request-context/request-context-decorator.spec.js +6 -0
- package/dist/esm/decorators/request-data/request-data-decorator.d.ts +10 -10
- package/dist/esm/decorators/request-data/request-data-decorator.js +10 -10
- package/dist/esm/decorators/request-data/request-data-decorator.spec.js +44 -32
- package/dist/esm/decorators/request-data/request-data-metadata.d.ts +1 -1
- package/dist/esm/decorators/rest-action/index.d.ts +3 -0
- package/dist/esm/decorators/rest-action/index.js +3 -0
- package/dist/esm/decorators/rest-action/rest-action-decorator.d.ts +57 -0
- package/dist/esm/decorators/rest-action/rest-action-decorator.js +52 -0
- package/dist/esm/decorators/rest-action/rest-action-decorator.spec.js +401 -0
- package/dist/esm/decorators/{action/action-metadata.d.ts → rest-action/rest-action-metadata.d.ts} +6 -6
- package/dist/esm/decorators/rest-action/rest-action-metadata.js +5 -0
- package/dist/esm/decorators/rest-action/rest-action-reflector.d.ts +22 -0
- package/dist/esm/decorators/{action/action-reflector.js → rest-action/rest-action-reflector.js} +6 -6
- package/dist/esm/decorators/{action/action-reflector.spec.js → rest-action/rest-action-reflector.spec.js} +13 -13
- package/dist/esm/decorators/rest-controller/index.d.ts +3 -0
- package/dist/esm/decorators/rest-controller/index.js +3 -0
- package/dist/esm/decorators/rest-controller/rest-controller-decorator.d.ts +14 -0
- package/dist/esm/decorators/{controller/controller-decorator.js → rest-controller/rest-controller-decorator.js} +5 -5
- package/dist/esm/decorators/{controller/controller-decorator.spec.js → rest-controller/rest-controller-decorator.spec.js} +15 -15
- package/dist/esm/decorators/{controller/controller-metadata.d.ts → rest-controller/rest-controller-metadata.d.ts} +5 -5
- package/dist/esm/decorators/rest-controller/rest-controller-metadata.js +5 -0
- package/dist/esm/decorators/rest-controller/rest-controller-reflector.d.ts +20 -0
- package/dist/esm/decorators/rest-controller/rest-controller-reflector.js +24 -0
- package/dist/esm/decorators/{controller/controller-reflector.spec.js → rest-controller/rest-controller-reflector.spec.js} +12 -12
- package/dist/esm/errors/not-a-controller-error.js +1 -1
- package/dist/esm/types.d.ts +0 -10
- package/dist/esm/utils/index.d.ts +0 -1
- package/dist/esm/utils/index.js +0 -1
- package/package.json +19 -19
- package/src/controller-registry.spec.ts +122 -122
- package/src/controller-registry.ts +33 -35
- package/src/debuggable-service.ts +17 -4
- package/src/decorators/{after/after-decorator.spec.ts → after-action/after-action-decorator.spec.ts} +19 -19
- package/src/decorators/{before/before-decorator.ts → after-action/after-action-decorator.ts} +9 -9
- package/src/decorators/{after/after-metadata.ts → after-action/after-action-metadata.ts} +5 -5
- package/src/decorators/{before/before-reflector.spec.ts → after-action/after-action-reflector.spec.ts} +33 -23
- package/src/decorators/{before/before-reflector.ts → after-action/after-action-reflector.ts} +13 -9
- package/src/decorators/after-action/index.ts +3 -0
- package/src/decorators/{before/before-decorator.spec.ts → before-action/before-action-decorator.spec.ts} +19 -19
- package/src/decorators/{after/after-decorator.ts → before-action/before-action-decorator.ts} +9 -9
- package/src/decorators/before-action/before-action-metadata.ts +17 -0
- package/src/decorators/{after/after-reflector.spec.ts → before-action/before-action-reflector.spec.ts} +40 -23
- package/src/decorators/{after/after-reflector.ts → before-action/before-action-reflector.ts} +18 -9
- package/src/decorators/before-action/index.ts +3 -0
- package/src/decorators/index.ts +4 -4
- package/src/decorators/request-context/request-context-decorator.spec.ts +7 -0
- package/src/decorators/request-context/request-context-decorator.ts +4 -4
- package/src/decorators/request-data/request-data-decorator.spec.ts +45 -32
- package/src/decorators/request-data/request-data-decorator.ts +10 -10
- package/src/decorators/request-data/request-data-metadata.ts +1 -1
- package/src/decorators/rest-action/index.ts +3 -0
- package/src/decorators/rest-action/rest-action-decorator.spec.ts +325 -0
- package/src/decorators/rest-action/rest-action-decorator.ts +166 -0
- package/src/decorators/{action/action-metadata.ts → rest-action/rest-action-metadata.ts} +7 -7
- package/src/decorators/{action/action-reflector.spec.ts → rest-action/rest-action-reflector.spec.ts} +13 -13
- package/src/decorators/rest-action/rest-action-reflector.ts +41 -0
- package/src/decorators/rest-controller/index.ts +3 -0
- package/src/decorators/{controller/controller-decorator.spec.ts → rest-controller/rest-controller-decorator.spec.ts} +16 -16
- package/src/decorators/{controller/controller-decorator.ts → rest-controller/rest-controller-decorator.ts} +14 -10
- package/src/decorators/{controller/controller-metadata.ts → rest-controller/rest-controller-metadata.ts} +6 -7
- package/src/decorators/{controller/controller-reflector.spec.ts → rest-controller/rest-controller-reflector.spec.ts} +21 -12
- package/src/decorators/rest-controller/rest-controller-reflector.ts +32 -0
- package/src/errors/not-a-controller-error.ts +4 -1
- package/src/types.ts +0 -10
- package/src/utils/index.ts +0 -1
- package/README-ru.md +0 -268
- package/dist/esm/decorators/action/action-decorator.d.ts +0 -52
- package/dist/esm/decorators/action/action-decorator.js +0 -62
- package/dist/esm/decorators/action/action-decorator.spec.js +0 -59
- package/dist/esm/decorators/action/action-metadata.js +0 -5
- package/dist/esm/decorators/action/action-reflector.d.ts +0 -22
- package/dist/esm/decorators/action/index.d.ts +0 -3
- package/dist/esm/decorators/action/index.js +0 -3
- package/dist/esm/decorators/after/after-decorator.d.ts +0 -9
- package/dist/esm/decorators/after/after-metadata.js +0 -5
- package/dist/esm/decorators/after/index.d.ts +0 -3
- package/dist/esm/decorators/after/index.js +0 -3
- package/dist/esm/decorators/before/before-decorator.d.ts +0 -9
- package/dist/esm/decorators/before/before-metadata.js +0 -5
- package/dist/esm/decorators/before/index.d.ts +0 -3
- package/dist/esm/decorators/before/index.js +0 -3
- package/dist/esm/decorators/controller/controller-decorator.d.ts +0 -14
- package/dist/esm/decorators/controller/controller-metadata.js +0 -5
- package/dist/esm/decorators/controller/controller-reflector.d.ts +0 -20
- package/dist/esm/decorators/controller/controller-reflector.js +0 -24
- package/dist/esm/decorators/controller/index.d.ts +0 -3
- package/dist/esm/decorators/controller/index.js +0 -3
- package/dist/esm/utils/create-debugger.d.ts +0 -44
- package/dist/esm/utils/create-debugger.js +0 -81
- package/dist/esm/utils/create-debugger.spec.d.ts +0 -1
- package/dist/esm/utils/create-debugger.spec.js +0 -8
- package/src/decorators/action/action-decorator.spec.ts +0 -42
- package/src/decorators/action/action-decorator.ts +0 -98
- package/src/decorators/action/action-reflector.ts +0 -38
- package/src/decorators/action/index.ts +0 -3
- package/src/decorators/after/index.ts +0 -3
- package/src/decorators/before/before-metadata.ts +0 -17
- package/src/decorators/before/index.ts +0 -3
- package/src/decorators/controller/controller-reflector.ts +0 -28
- package/src/decorators/controller/index.ts +0 -3
- package/src/utils/create-debugger.spec.ts +0 -9
- package/src/utils/create-debugger.ts +0 -98
- /package/dist/esm/decorators/{action/action-decorator.spec.d.ts → after-action/after-action-decorator.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{action/action-reflector.spec.d.ts → after-action/after-action-reflector.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{after/after-decorator.spec.d.ts → before-action/before-action-decorator.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{after/after-reflector.spec.d.ts → before-action/before-action-reflector.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{before/before-decorator.spec.d.ts → rest-action/rest-action-decorator.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{before/before-reflector.spec.d.ts → rest-action/rest-action-reflector.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{controller/controller-decorator.spec.d.ts → rest-controller/rest-controller-decorator.spec.d.ts} +0 -0
- /package/dist/esm/decorators/{controller/controller-reflector.spec.d.ts → rest-controller/rest-controller-reflector.spec.d.ts} +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
import {expect} from 'chai';
|
2
|
-
import {
|
3
|
-
import {
|
4
|
-
import {
|
2
|
+
import {restController} from './rest-controller-decorator.js';
|
3
|
+
import {RestControllerOptions} from './rest-controller-decorator.js';
|
4
|
+
import {RestControllerReflector} from './rest-controller-reflector.js';
|
5
5
|
|
6
|
-
describe('
|
6
|
+
describe('restController', function () {
|
7
7
|
it('does not require options', function () {
|
8
|
-
@
|
8
|
+
@restController()
|
9
9
|
class Target {}
|
10
|
-
const res =
|
10
|
+
const res = RestControllerReflector.getMetadata(Target);
|
11
11
|
expect(res).to.be.eql({className: 'Target'});
|
12
12
|
});
|
13
13
|
|
@@ -18,9 +18,9 @@ describe('controller', function () {
|
|
18
18
|
after: () => undefined,
|
19
19
|
extraOption: 'extraOption',
|
20
20
|
};
|
21
|
-
@
|
21
|
+
@restController(options)
|
22
22
|
class Target {}
|
23
|
-
const res =
|
23
|
+
const res = RestControllerReflector.getMetadata(Target);
|
24
24
|
expect(res).to.be.eql({
|
25
25
|
...options,
|
26
26
|
className: 'Target',
|
@@ -28,31 +28,31 @@ describe('controller', function () {
|
|
28
28
|
});
|
29
29
|
|
30
30
|
it('overrides given "className" option by the target class name', function () {
|
31
|
-
@
|
31
|
+
@restController({className: 'myClassName'} as RestControllerOptions)
|
32
32
|
class Target {}
|
33
|
-
const res =
|
33
|
+
const res = RestControllerReflector.getMetadata(Target);
|
34
34
|
expect(res).to.be.eql({className: 'Target'});
|
35
35
|
});
|
36
36
|
|
37
37
|
it('allows to pass the path option to the first parameter', function () {
|
38
|
-
@
|
38
|
+
@restController('myPath')
|
39
39
|
class Target {}
|
40
|
-
const res =
|
40
|
+
const res = RestControllerReflector.getMetadata(Target);
|
41
41
|
expect(res).to.be.eql({className: 'Target', path: 'myPath'});
|
42
42
|
});
|
43
43
|
|
44
44
|
it('merges two given arguments in the target metadata', function () {
|
45
45
|
const before = () => undefined;
|
46
|
-
@
|
46
|
+
@restController('myPath', {before})
|
47
47
|
class Target {}
|
48
|
-
const res =
|
48
|
+
const res = RestControllerReflector.getMetadata(Target);
|
49
49
|
expect(res).to.be.eql({className: 'Target', path: 'myPath', before});
|
50
50
|
});
|
51
51
|
|
52
52
|
it('overrides the path option by the first argument', function () {
|
53
|
-
@
|
53
|
+
@restController('myPath1', {path: 'myPath2'})
|
54
54
|
class Target {}
|
55
|
-
const res =
|
55
|
+
const res = RestControllerReflector.getMetadata(Target);
|
56
56
|
expect(res).to.be.eql({className: 'Target', path: 'myPath1'});
|
57
57
|
});
|
58
58
|
});
|
@@ -1,29 +1,33 @@
|
|
1
1
|
import {Flatten} from '../../types.js';
|
2
2
|
import {Constructor} from '../../types.js';
|
3
3
|
import {DecoratorTargetType} from '@e22m4u/ts-reflector';
|
4
|
-
import {ControllerMetadata} from './controller-metadata.js';
|
5
4
|
import {getDecoratorTargetType} from '@e22m4u/ts-reflector';
|
6
|
-
import {
|
5
|
+
import {RestControllerMetadata} from './rest-controller-metadata.js';
|
6
|
+
import {RestControllerReflector} from './rest-controller-reflector.js';
|
7
7
|
|
8
8
|
/**
|
9
|
-
*
|
9
|
+
* Rest controller options.
|
10
10
|
*/
|
11
|
-
export type
|
11
|
+
export type RestControllerOptions = Flatten<
|
12
|
+
Omit<RestControllerMetadata, 'className'>
|
13
|
+
>;
|
12
14
|
|
13
15
|
/**
|
14
|
-
*
|
16
|
+
* Rest controller decorator.
|
15
17
|
*
|
16
18
|
* @param pathOrOptions
|
17
19
|
* @param options
|
18
20
|
*/
|
19
|
-
export function
|
20
|
-
pathOrOptions?: string |
|
21
|
-
options?:
|
21
|
+
export function restController<T extends object>(
|
22
|
+
pathOrOptions?: string | RestControllerOptions,
|
23
|
+
options?: RestControllerOptions,
|
22
24
|
) {
|
23
25
|
return function (target: Constructor<T>) {
|
24
26
|
const decoratorType = getDecoratorTargetType(target);
|
25
27
|
if (decoratorType !== DecoratorTargetType.CONSTRUCTOR)
|
26
|
-
throw new Error(
|
28
|
+
throw new Error(
|
29
|
+
'@restController decorator is only supported on a class.',
|
30
|
+
);
|
27
31
|
// если первый аргумент является строкой,
|
28
32
|
// то значение используется в качестве
|
29
33
|
// базового пути контроллера
|
@@ -48,7 +52,7 @@ export function controller<T extends object>(
|
|
48
52
|
else if (typeof pathOrOptions === 'object') {
|
49
53
|
options = pathOrOptions;
|
50
54
|
}
|
51
|
-
|
55
|
+
RestControllerReflector.setMetadata(
|
52
56
|
{...options, className: target.name},
|
53
57
|
target,
|
54
58
|
);
|
@@ -1,11 +1,11 @@
|
|
1
|
+
import {MetadataKey} from '@e22m4u/ts-reflector';
|
1
2
|
import {RoutePreHandler} from '@e22m4u/js-trie-router';
|
2
3
|
import {RoutePostHandler} from '@e22m4u/js-trie-router';
|
3
|
-
import {MetadataKey} from '@e22m4u/ts-reflector';
|
4
4
|
|
5
5
|
/**
|
6
|
-
*
|
6
|
+
* Rest controller metadata.
|
7
7
|
*/
|
8
|
-
export type
|
8
|
+
export type RestControllerMetadata = {
|
9
9
|
className: string;
|
10
10
|
path?: string;
|
11
11
|
before?: RoutePreHandler | RoutePreHandler[];
|
@@ -13,8 +13,7 @@ export type ControllerMetadata = {
|
|
13
13
|
};
|
14
14
|
|
15
15
|
/**
|
16
|
-
*
|
16
|
+
* Rest controller metadata key.
|
17
17
|
*/
|
18
|
-
export const
|
19
|
-
'
|
20
|
-
);
|
18
|
+
export const REST_CONTROLLER_METADATA_KEY =
|
19
|
+
new MetadataKey<RestControllerMetadata>('restControllerMetadataKey');
|
@@ -1,16 +1,19 @@
|
|
1
1
|
import {expect} from 'chai';
|
2
2
|
import {describe} from 'mocha';
|
3
3
|
import {Reflector} from '@e22m4u/ts-reflector';
|
4
|
-
import {
|
5
|
-
import {
|
4
|
+
import {RestControllerReflector} from './rest-controller-reflector.js';
|
5
|
+
import {REST_CONTROLLER_METADATA_KEY} from './rest-controller-metadata.js';
|
6
6
|
|
7
|
-
describe('
|
7
|
+
describe('RestControllerReflector', function () {
|
8
8
|
describe('setMetadata', function () {
|
9
9
|
it('sets a given value as target metadata', function () {
|
10
10
|
class Target {}
|
11
11
|
const md = {className: 'Target'};
|
12
|
-
|
13
|
-
const res = Reflector.getOwnMetadata(
|
12
|
+
RestControllerReflector.setMetadata(md, Target);
|
13
|
+
const res = Reflector.getOwnMetadata(
|
14
|
+
REST_CONTROLLER_METADATA_KEY,
|
15
|
+
Target,
|
16
|
+
);
|
14
17
|
expect(res).to.be.eq(md);
|
15
18
|
});
|
16
19
|
|
@@ -18,11 +21,17 @@ describe('ControllerReflector', function () {
|
|
18
21
|
class Target {}
|
19
22
|
const md1 = {className: 'Target', path: 'path1'};
|
20
23
|
const md2 = {className: 'Target', path: 'path2'};
|
21
|
-
|
22
|
-
const res1 = Reflector.getOwnMetadata(
|
24
|
+
RestControllerReflector.setMetadata(md1, Target);
|
25
|
+
const res1 = Reflector.getOwnMetadata(
|
26
|
+
REST_CONTROLLER_METADATA_KEY,
|
27
|
+
Target,
|
28
|
+
);
|
23
29
|
expect(res1).to.be.eq(md1);
|
24
|
-
|
25
|
-
const res2 = Reflector.getOwnMetadata(
|
30
|
+
RestControllerReflector.setMetadata(md2, Target);
|
31
|
+
const res2 = Reflector.getOwnMetadata(
|
32
|
+
REST_CONTROLLER_METADATA_KEY,
|
33
|
+
Target,
|
34
|
+
);
|
26
35
|
expect(res2).to.be.eq(md2);
|
27
36
|
});
|
28
37
|
});
|
@@ -31,14 +40,14 @@ describe('ControllerReflector', function () {
|
|
31
40
|
it('returns an existing metadata of the target', function () {
|
32
41
|
class Target {}
|
33
42
|
const md = {className: 'Target'};
|
34
|
-
Reflector.defineMetadata(
|
35
|
-
const res =
|
43
|
+
Reflector.defineMetadata(REST_CONTROLLER_METADATA_KEY, md, Target);
|
44
|
+
const res = RestControllerReflector.getMetadata(Target);
|
36
45
|
expect(res).to.be.eq(md);
|
37
46
|
});
|
38
47
|
|
39
48
|
it('returns undefined if no metadata', function () {
|
40
49
|
class Target {}
|
41
|
-
const res =
|
50
|
+
const res = RestControllerReflector.getMetadata(Target);
|
42
51
|
expect(res).to.be.undefined;
|
43
52
|
});
|
44
53
|
});
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import {Constructor} from '../../types.js';
|
2
|
+
import {Reflector} from '@e22m4u/ts-reflector';
|
3
|
+
import {RestControllerMetadata} from './rest-controller-metadata.js';
|
4
|
+
import {REST_CONTROLLER_METADATA_KEY} from './rest-controller-metadata.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Rest controller reflector.
|
8
|
+
*/
|
9
|
+
export class RestControllerReflector {
|
10
|
+
/**
|
11
|
+
* Set metadata.
|
12
|
+
*
|
13
|
+
* @param metadata
|
14
|
+
* @param target
|
15
|
+
*/
|
16
|
+
static setMetadata(metadata: RestControllerMetadata, target: Constructor) {
|
17
|
+
return Reflector.defineMetadata(
|
18
|
+
REST_CONTROLLER_METADATA_KEY,
|
19
|
+
metadata,
|
20
|
+
target,
|
21
|
+
);
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Get metadata.
|
26
|
+
*
|
27
|
+
* @param target
|
28
|
+
*/
|
29
|
+
static getMetadata(target: Constructor): RestControllerMetadata | undefined {
|
30
|
+
return Reflector.getOwnMetadata(REST_CONTROLLER_METADATA_KEY, target);
|
31
|
+
}
|
32
|
+
}
|
@@ -10,6 +10,9 @@ export class NotAControllerError extends Errorf {
|
|
10
10
|
* @param value
|
11
11
|
*/
|
12
12
|
constructor(value: unknown) {
|
13
|
-
super(
|
13
|
+
super(
|
14
|
+
'%v is not a controller, do use @restController decorator on it.',
|
15
|
+
value,
|
16
|
+
);
|
14
17
|
}
|
15
18
|
}
|
package/src/types.ts
CHANGED
@@ -36,16 +36,6 @@ export type Identity<T> = T;
|
|
36
36
|
*/
|
37
37
|
export type Flatten<T> = Identity<{[k in keyof T]: T[k]}>;
|
38
38
|
|
39
|
-
/**
|
40
|
-
* A promise or value.
|
41
|
-
*/
|
42
|
-
export type ValueOrPromise<T> = T | PromiseLike<T>;
|
43
|
-
|
44
|
-
/**
|
45
|
-
* Plain object.
|
46
|
-
*/
|
47
|
-
export type PlainObject = {[key: string]: unknown};
|
48
|
-
|
49
39
|
/**
|
50
40
|
* Remove null and undefined from T.
|
51
41
|
*/
|
package/src/utils/index.ts
CHANGED
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 {field} 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
|
-
@field('username', { // поле "username" в теле запроса
|
49
|
-
type: DataType.STRING, // тип параметра допускает только строки
|
50
|
-
required: true, // параметр является обязательным
|
51
|
-
})
|
52
|
-
username: string,
|
53
|
-
@field('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
|
-
- `@field` - поле в теле запроса
|
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
|
@@ -1,52 +0,0 @@
|
|
1
|
-
import { Flatten } from '../../types.js';
|
2
|
-
import { Prototype } from '../../types.js';
|
3
|
-
import { ActionMetadata } from './action-metadata.js';
|
4
|
-
/**
|
5
|
-
* Action options.
|
6
|
-
*/
|
7
|
-
export type ActionOptions = Flatten<Omit<ActionMetadata, 'propertyKey'>>;
|
8
|
-
/**
|
9
|
-
* Action decorator.
|
10
|
-
*
|
11
|
-
* @param options
|
12
|
-
*/
|
13
|
-
export declare function action<T extends object>(options: ActionOptions): (target: Prototype<T>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
14
|
-
/**
|
15
|
-
* Action method options.
|
16
|
-
*/
|
17
|
-
export type ActionMethodOptions = Flatten<Omit<ActionOptions, 'method' | 'path'>>;
|
18
|
-
/**
|
19
|
-
* Get decorator.
|
20
|
-
*
|
21
|
-
* @param path
|
22
|
-
* @param options
|
23
|
-
*/
|
24
|
-
export declare const get: (path: string, options?: ActionMethodOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
25
|
-
/**
|
26
|
-
* Post decorator.
|
27
|
-
*
|
28
|
-
* @param path
|
29
|
-
* @param options
|
30
|
-
*/
|
31
|
-
export declare const post: (path: string, options?: ActionMethodOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
32
|
-
/**
|
33
|
-
* Put decorator.
|
34
|
-
*
|
35
|
-
* @param path
|
36
|
-
* @param options
|
37
|
-
*/
|
38
|
-
export declare const put: (path: string, options?: ActionMethodOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
39
|
-
/**
|
40
|
-
* Patch decorator.
|
41
|
-
*
|
42
|
-
* @param path
|
43
|
-
* @param options
|
44
|
-
*/
|
45
|
-
export declare const patch: (path: string, options?: ActionMethodOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
46
|
-
/**
|
47
|
-
* Del decorator.
|
48
|
-
*
|
49
|
-
* @param path
|
50
|
-
* @param options
|
51
|
-
*/
|
52
|
-
export declare const del: (path: string, options?: ActionMethodOptions) => (target: Prototype<object>, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
@@ -1,62 +0,0 @@
|
|
1
|
-
import { HttpMethod } from '@e22m4u/js-trie-router';
|
2
|
-
import { ActionReflector } from './action-reflector.js';
|
3
|
-
import { DecoratorTargetType } from '@e22m4u/ts-reflector';
|
4
|
-
import { getDecoratorTargetType } from '@e22m4u/ts-reflector';
|
5
|
-
/**
|
6
|
-
* Action decorator.
|
7
|
-
*
|
8
|
-
* @param options
|
9
|
-
*/
|
10
|
-
export function action(options) {
|
11
|
-
return function (target, propertyKey, descriptor) {
|
12
|
-
const decoratorType = getDecoratorTargetType(target, propertyKey, descriptor);
|
13
|
-
if (decoratorType !== DecoratorTargetType.INSTANCE_METHOD)
|
14
|
-
throw new Error('@action decorator is only supported on an instance method.');
|
15
|
-
ActionReflector.setMetadata({ ...options, propertyKey }, target.constructor, propertyKey);
|
16
|
-
};
|
17
|
-
}
|
18
|
-
/**
|
19
|
-
* Get decorator.
|
20
|
-
*
|
21
|
-
* @param path
|
22
|
-
* @param options
|
23
|
-
*/
|
24
|
-
export const get = (path, options) => {
|
25
|
-
return action({ ...options, path, method: HttpMethod.GET });
|
26
|
-
};
|
27
|
-
/**
|
28
|
-
* Post decorator.
|
29
|
-
*
|
30
|
-
* @param path
|
31
|
-
* @param options
|
32
|
-
*/
|
33
|
-
export const post = (path, options) => {
|
34
|
-
return action({ ...options, path, method: HttpMethod.POST });
|
35
|
-
};
|
36
|
-
/**
|
37
|
-
* Put decorator.
|
38
|
-
*
|
39
|
-
* @param path
|
40
|
-
* @param options
|
41
|
-
*/
|
42
|
-
export const put = (path, options) => {
|
43
|
-
return action({ ...options, path, method: HttpMethod.PUT });
|
44
|
-
};
|
45
|
-
/**
|
46
|
-
* Patch decorator.
|
47
|
-
*
|
48
|
-
* @param path
|
49
|
-
* @param options
|
50
|
-
*/
|
51
|
-
export const patch = (path, options) => {
|
52
|
-
return action({ ...options, path, method: HttpMethod.PATCH });
|
53
|
-
};
|
54
|
-
/**
|
55
|
-
* Del decorator.
|
56
|
-
*
|
57
|
-
* @param path
|
58
|
-
* @param options
|
59
|
-
*/
|
60
|
-
export const del = (path, options) => {
|
61
|
-
return action({ ...options, path, method: HttpMethod.DELETE });
|
62
|
-
};
|