@deepkit/http 1.0.1-alpha.16 → 1.0.1-alpha.160
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/CHANGELOG.md +236 -0
- package/dist/cjs/index.d.ts +14 -10
- package/dist/cjs/index.js +19 -11
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/src/controllers.d.ts +10 -3
- package/dist/cjs/src/controllers.js +7 -3
- package/dist/cjs/src/controllers.js.map +1 -1
- package/dist/cjs/src/decorator.d.ts +144 -70
- package/dist/cjs/src/decorator.js +277 -102
- package/dist/cjs/src/decorator.js.map +1 -1
- package/dist/cjs/src/filter.d.ts +49 -0
- package/dist/cjs/src/filter.js +215 -0
- package/dist/cjs/src/filter.js.map +1 -0
- package/dist/cjs/src/http-app.d.ts +8 -0
- package/dist/cjs/src/http-app.js +16 -0
- package/dist/cjs/src/http-app.js.map +1 -0
- package/dist/cjs/src/http.d.ts +131 -32
- package/dist/cjs/src/http.js +523 -122
- package/dist/cjs/src/http.js.map +1 -1
- package/dist/cjs/src/kernel.d.ts +50 -9
- package/dist/cjs/src/kernel.js +109 -98
- package/dist/cjs/src/kernel.js.map +1 -1
- package/dist/cjs/src/logger.d.ts +3 -3
- package/dist/cjs/src/logger.js +9 -12
- package/dist/cjs/src/logger.js.map +1 -1
- package/dist/cjs/src/middleware.d.ts +61 -0
- package/dist/cjs/src/middleware.js +95 -0
- package/dist/cjs/src/middleware.js.map +1 -0
- package/dist/cjs/src/model.d.ts +270 -4
- package/dist/cjs/src/model.js +401 -3
- package/dist/cjs/src/model.js.map +1 -1
- package/dist/cjs/src/module.config.d.ts +149 -4
- package/dist/cjs/src/module.config.js +11 -6
- package/dist/cjs/src/module.config.js.map +1 -1
- package/dist/cjs/src/module.d.ts +14 -32
- package/dist/cjs/src/module.js +122 -7
- package/dist/cjs/src/module.js.map +1 -1
- package/dist/cjs/src/request-parser.d.ts +37 -0
- package/dist/cjs/src/request-parser.js +382 -0
- package/dist/cjs/src/request-parser.js.map +1 -0
- package/dist/cjs/src/router.d.ts +174 -75
- package/dist/cjs/src/router.js +469 -288
- package/dist/cjs/src/router.js.map +1 -1
- package/dist/cjs/src/static-serving.d.ts +32 -4
- package/dist/cjs/src/static-serving.js +115 -71
- package/dist/cjs/src/static-serving.js.map +1 -1
- package/dist/cjs/src/utils.js +2 -2
- package/dist/cjs/src/utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -2916
- package/dist/esm/index.d.ts +14 -10
- package/dist/esm/index.js +14 -10
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/src/controllers.d.ts +10 -3
- package/dist/esm/src/controllers.js +7 -3
- package/dist/esm/src/controllers.js.map +1 -1
- package/dist/esm/src/decorator.d.ts +144 -70
- package/dist/esm/src/decorator.js +272 -99
- package/dist/esm/src/decorator.js.map +1 -1
- package/dist/esm/src/filter.d.ts +49 -0
- package/dist/esm/src/filter.js +209 -0
- package/dist/esm/src/filter.js.map +1 -0
- package/dist/esm/src/http-app.d.ts +8 -0
- package/dist/esm/src/http-app.js +12 -0
- package/dist/esm/src/http-app.js.map +1 -0
- package/dist/esm/src/http.d.ts +131 -32
- package/dist/esm/src/http.js +504 -121
- package/dist/esm/src/http.js.map +1 -1
- package/dist/esm/src/kernel.d.ts +50 -9
- package/dist/esm/src/kernel.js +110 -100
- package/dist/esm/src/kernel.js.map +1 -1
- package/dist/esm/src/logger.d.ts +3 -3
- package/dist/esm/src/logger.js +7 -11
- package/dist/esm/src/logger.js.map +1 -1
- package/dist/esm/src/middleware.d.ts +61 -0
- package/dist/esm/src/middleware.js +90 -0
- package/dist/esm/src/middleware.js.map +1 -0
- package/dist/esm/src/model.d.ts +270 -4
- package/dist/esm/src/model.js +357 -1
- package/dist/esm/src/model.js.map +1 -1
- package/dist/esm/src/module.config.d.ts +149 -4
- package/dist/esm/src/module.config.js +9 -5
- package/dist/esm/src/module.config.js.map +1 -1
- package/dist/esm/src/module.d.ts +14 -32
- package/dist/esm/src/module.js +121 -7
- package/dist/esm/src/module.js.map +1 -1
- package/dist/esm/src/request-parser.d.ts +37 -0
- package/dist/esm/src/request-parser.js +372 -0
- package/dist/esm/src/request-parser.js.map +1 -0
- package/dist/esm/src/router.d.ts +174 -75
- package/dist/esm/src/router.js +463 -285
- package/dist/esm/src/router.js.map +1 -1
- package/dist/esm/src/static-serving.d.ts +32 -4
- package/dist/esm/src/static-serving.js +107 -65
- package/dist/esm/src/static-serving.js.map +1 -1
- package/dist/esm/src/utils.js +1 -0
- package/dist/esm/src/utils.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -2916
- package/index.ts +14 -10
- package/package.json +30 -19
- package/src/controllers.ts +4 -3
- package/src/decorator.ts +242 -104
- package/src/filter.ts +224 -0
- package/src/http-app.ts +11 -0
- package/src/http.ts +501 -100
- package/src/kernel.ts +128 -80
- package/src/logger.ts +4 -6
- package/src/middleware.ts +116 -0
- package/src/model.ts +516 -5
- package/src/module.config.ts +168 -5
- package/src/module.ts +120 -7
- package/src/request-parser.ts +430 -0
- package/src/router.ts +546 -317
- package/src/static-serving.ts +120 -50
- package/src/utils.ts +0 -2
- package/tsconfig.esm.json +7 -7
- package/tsconfig.json +18 -11
- package/tsconfig.spec.json +8 -0
- package/dist/cjs/tests/router.spec.d.ts +0 -1
- package/dist/cjs/tests/router.spec.js +0 -481
- package/dist/cjs/tests/router.spec.js.map +0 -1
- package/dist/esm/tests/router.spec.d.ts +0 -1
- package/dist/esm/tests/router.spec.js +0 -479
- package/dist/esm/tests/router.spec.js.map +0 -1
- package/tests/router.spec.ts +0 -347
package/index.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
export * from './src/decorator';
|
|
2
|
-
export * from './src/http';
|
|
3
|
-
export * from './src/
|
|
4
|
-
export * from './src/
|
|
5
|
-
export * from './src/
|
|
6
|
-
export * from './src/
|
|
7
|
-
export * from './src/
|
|
8
|
-
export * from './src/
|
|
9
|
-
export * from './src/module.
|
|
10
|
-
export * from './src/
|
|
1
|
+
export * from './src/decorator.js';
|
|
2
|
+
export * from './src/http.js';
|
|
3
|
+
export * from './src/http-app.js';
|
|
4
|
+
export * from './src/model.js';
|
|
5
|
+
export * from './src/logger.js';
|
|
6
|
+
export * from './src/router.js';
|
|
7
|
+
export * from './src/static-serving.js';
|
|
8
|
+
export * from './src/kernel.js';
|
|
9
|
+
export * from './src/module.js';
|
|
10
|
+
export * from './src/module.config.js';
|
|
11
|
+
export * from './src/controllers.js';
|
|
12
|
+
export * from './src/middleware.js';
|
|
13
|
+
export * from './src/filter.js';
|
|
14
|
+
export * from './src/utils.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepkit/http",
|
|
3
|
-
"version": "1.0.1-alpha.
|
|
3
|
+
"version": "1.0.1-alpha.160",
|
|
4
4
|
"description": "Deepkit HTTP server and router.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"types": "./dist/cjs/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./dist/cjs/index.d.ts",
|
|
11
12
|
"require": "./dist/cjs/index.js",
|
|
12
13
|
"default": "./dist/esm/index.js"
|
|
13
14
|
}
|
|
@@ -30,34 +31,44 @@
|
|
|
30
31
|
"@deepkit/stopwatch": "^1.0.1-alpha.13",
|
|
31
32
|
"@deepkit/template": "^1.0.1-alpha.13",
|
|
32
33
|
"@deepkit/type": "^1.0.1-alpha.13",
|
|
33
|
-
"@deepkit/workflow": "^1.0.1-alpha.13"
|
|
34
|
-
"reflect-metadata": "^0.1.13"
|
|
34
|
+
"@deepkit/workflow": "^1.0.1-alpha.13"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"formidable": "^
|
|
38
|
-
"
|
|
37
|
+
"formidable": "^3.5.2",
|
|
38
|
+
"qs": "^6.14.0",
|
|
39
|
+
"send": "^1.1.0"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@deepkit/app": "^1.0.1-alpha.
|
|
42
|
-
"@deepkit/core": "^1.0.1-alpha.
|
|
43
|
-
"@deepkit/event": "^1.0.1-alpha.
|
|
44
|
-
"@deepkit/injector": "^1.0.1-alpha.
|
|
45
|
-
"@deepkit/logger": "^1.0.1-alpha.
|
|
46
|
-
"@deepkit/stopwatch": "^1.0.1-alpha.
|
|
47
|
-
"@deepkit/template": "^1.0.1-alpha.
|
|
48
|
-
"@deepkit/type": "^1.0.1-alpha.
|
|
49
|
-
"@deepkit/workflow": "^1.0.1-alpha.
|
|
50
|
-
"@types/
|
|
51
|
-
"@types/
|
|
52
|
-
"
|
|
42
|
+
"@deepkit/app": "^1.0.1-alpha.160",
|
|
43
|
+
"@deepkit/core": "^1.0.1-alpha.158",
|
|
44
|
+
"@deepkit/event": "^1.0.1-alpha.160",
|
|
45
|
+
"@deepkit/injector": "^1.0.1-alpha.160",
|
|
46
|
+
"@deepkit/logger": "^1.0.1-alpha.160",
|
|
47
|
+
"@deepkit/stopwatch": "^1.0.1-alpha.160",
|
|
48
|
+
"@deepkit/template": "^1.0.1-alpha.160",
|
|
49
|
+
"@deepkit/type": "^1.0.1-alpha.160",
|
|
50
|
+
"@deepkit/workflow": "^1.0.1-alpha.160",
|
|
51
|
+
"@types/formidable": "^3.4.5",
|
|
52
|
+
"@types/node": "^22.13.1",
|
|
53
|
+
"@types/send": "^0.14.6"
|
|
53
54
|
},
|
|
54
55
|
"jest": {
|
|
56
|
+
"testEnvironment": "node",
|
|
55
57
|
"transform": {
|
|
56
|
-
"^.+\\.(ts|tsx)$":
|
|
58
|
+
"^.+\\.(ts|tsx)$": [
|
|
59
|
+
"ts-jest",
|
|
60
|
+
{
|
|
61
|
+
"tsconfig": "<rootDir>/tsconfig.spec.json"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
57
64
|
},
|
|
65
|
+
"moduleNameMapper": {
|
|
66
|
+
"(.+)\\.js": "$1"
|
|
67
|
+
},
|
|
68
|
+
"resolver": "../../jest-resolver.js",
|
|
58
69
|
"testMatch": [
|
|
59
70
|
"**/tests/**/*.spec.ts"
|
|
60
71
|
]
|
|
61
72
|
},
|
|
62
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "52a703a1f6747c59e77cbf44d80d3bc5b1424ee6"
|
|
63
74
|
}
|
package/src/controllers.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ClassType } from '@deepkit/core';
|
|
2
|
+
import { InjectorModule } from '@deepkit/injector';
|
|
2
3
|
|
|
3
4
|
export class HttpControllers {
|
|
4
|
-
constructor(public readonly controllers: ClassType[]) {
|
|
5
|
+
constructor(public readonly controllers: {controller: ClassType, module: InjectorModule<any>}[] = []) {
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
public add(controller: ClassType) {
|
|
8
|
-
this.controllers.push(controller);
|
|
8
|
+
public add(controller: ClassType, module: InjectorModule<any>) {
|
|
9
|
+
this.controllers.push({controller, module});
|
|
9
10
|
}
|
|
10
11
|
}
|
package/src/decorator.ts
CHANGED
|
@@ -8,21 +8,48 @@
|
|
|
8
8
|
* You should have received a copy of the MIT License along with this program.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { ClassType } from '@deepkit/core';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
import { ClassType, isClass, urlJoin } from '@deepkit/core';
|
|
12
|
+
import {
|
|
13
|
+
ClassDecoratorResult,
|
|
14
|
+
createClassDecoratorContext,
|
|
15
|
+
createPropertyDecoratorContext,
|
|
16
|
+
DecoratorAndFetchSignature,
|
|
17
|
+
DualDecorator,
|
|
18
|
+
ExtractApiDataType,
|
|
19
|
+
ExtractClass,
|
|
20
|
+
isDecoratorContext,
|
|
21
|
+
mergeDecorator,
|
|
22
|
+
PropertyDecoratorFn,
|
|
23
|
+
ReceiveType,
|
|
24
|
+
resolveReceiveType,
|
|
25
|
+
SerializationOptions,
|
|
26
|
+
Serializer,
|
|
27
|
+
Type,
|
|
28
|
+
UnionToIntersection
|
|
29
|
+
} from '@deepkit/type';
|
|
30
|
+
import { RouteParameterResolver } from './router.js';
|
|
31
|
+
import { httpMiddleware, HttpMiddleware, HttpMiddlewareConfig, HttpMiddlewareFn } from './middleware.js';
|
|
32
|
+
|
|
33
|
+
type HttpActionMiddleware = (() => HttpMiddlewareConfig) | ClassType<HttpMiddleware> | HttpMiddlewareFn;
|
|
34
|
+
|
|
35
|
+
function isMiddlewareClassTypeOrFn(v: HttpActionMiddleware): v is ClassType<HttpMiddleware> | HttpMiddlewareFn {
|
|
36
|
+
return isClass(v) || !isDecoratorContext(httpMiddleware, v);
|
|
17
37
|
}
|
|
18
38
|
|
|
19
|
-
class HttpController {
|
|
39
|
+
export class HttpController {
|
|
20
40
|
baseUrl: string = '';
|
|
21
|
-
|
|
41
|
+
actions = new Set<HttpAction>();
|
|
22
42
|
groups: string[] = [];
|
|
23
43
|
|
|
44
|
+
middlewares: (() => HttpMiddlewareConfig)[] = [];
|
|
45
|
+
|
|
46
|
+
resolverForToken: Map<any, ClassType> = new Map();
|
|
47
|
+
resolverForParameterName: Map<string, ClassType> = new Map();
|
|
48
|
+
|
|
49
|
+
private actionsProcessed = new Set<HttpAction>();
|
|
50
|
+
|
|
24
51
|
getUrl(action: HttpAction): string {
|
|
25
|
-
return
|
|
52
|
+
return urlJoin('/', this.baseUrl, action.path);
|
|
26
53
|
}
|
|
27
54
|
|
|
28
55
|
addAction(action: HttpAction) {
|
|
@@ -30,15 +57,25 @@ class HttpController {
|
|
|
30
57
|
}
|
|
31
58
|
|
|
32
59
|
getActions(): Set<HttpAction> {
|
|
33
|
-
for (const
|
|
34
|
-
|
|
35
|
-
|
|
60
|
+
for (const action of this.actions) {
|
|
61
|
+
if (!this.actionsProcessed.has(action)) {
|
|
62
|
+
action.groups = [
|
|
63
|
+
...this.groups,
|
|
64
|
+
...action.groups.filter((g) => !this.groups.includes(g)),
|
|
65
|
+
];
|
|
66
|
+
this.actionsProcessed.add(action);
|
|
36
67
|
}
|
|
37
68
|
}
|
|
38
69
|
|
|
39
70
|
return this.actions;
|
|
40
71
|
}
|
|
41
72
|
|
|
73
|
+
removeAction(methodName: string): void {
|
|
74
|
+
const action = this.getAction(methodName);
|
|
75
|
+
this.actions.delete(action);
|
|
76
|
+
this.actionsProcessed.delete(action);
|
|
77
|
+
}
|
|
78
|
+
|
|
42
79
|
getAction(methodName: string): HttpAction {
|
|
43
80
|
for (const a of this.getActions()) {
|
|
44
81
|
if (a.methodName === methodName) return a;
|
|
@@ -49,7 +86,7 @@ class HttpController {
|
|
|
49
86
|
|
|
50
87
|
export class HttpActionParameter {
|
|
51
88
|
name: string = '';
|
|
52
|
-
type?: 'body' | 'query';
|
|
89
|
+
type?: 'body' | 'query' | 'queries';
|
|
53
90
|
|
|
54
91
|
/**
|
|
55
92
|
* undefined = propertyName, '' === root, else given path
|
|
@@ -63,47 +100,120 @@ export class HttpAction {
|
|
|
63
100
|
description: string = '';
|
|
64
101
|
category: string = '';
|
|
65
102
|
path: string = '';
|
|
66
|
-
|
|
103
|
+
httpMethods: string[] = [];
|
|
67
104
|
methodName: string = '';
|
|
68
105
|
groups: string[] = [];
|
|
106
|
+
serializer?: Serializer;
|
|
107
|
+
middlewares: (() => HttpMiddlewareConfig)[] = [];
|
|
108
|
+
serializationOptions?: SerializationOptions;
|
|
69
109
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* This is only filled when the user used @http.body() for example on an method argument.
|
|
74
|
-
*/
|
|
75
|
-
parameters: { [name: string]: HttpActionParameter } = {};
|
|
110
|
+
resolverForToken: Map<any, ClassType> = new Map();
|
|
111
|
+
resolverForParameterName: Map<string, ClassType> = new Map();
|
|
76
112
|
|
|
77
113
|
/**
|
|
78
114
|
* An arbitrary data container the user can use to store app specific settings/values.
|
|
79
115
|
*/
|
|
80
116
|
data = new Map<any, any>();
|
|
81
117
|
|
|
82
|
-
|
|
118
|
+
responses: { statusCode: number, description: string, type?: Type }[] = [];
|
|
83
119
|
}
|
|
84
120
|
|
|
85
|
-
export class
|
|
121
|
+
export class HttpControllerDecorator {
|
|
86
122
|
t = new HttpController;
|
|
87
123
|
|
|
88
124
|
controller(baseUrl: string = '') {
|
|
89
125
|
this.t.baseUrl = baseUrl;
|
|
90
126
|
}
|
|
91
127
|
|
|
92
|
-
|
|
128
|
+
group(...group: string[]) {
|
|
93
129
|
this.t.groups.push(...group);
|
|
94
130
|
}
|
|
95
131
|
|
|
132
|
+
middleware(...middlewares: HttpActionMiddleware[]) {
|
|
133
|
+
this.t.middlewares.push(...middlewares.map(v => isMiddlewareClassTypeOrFn(v) ? httpMiddleware.for(v) : v));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Adds a parameter resolver for parameters based on the class type. Use .resolveParameterByName() for name-based resolving.
|
|
138
|
+
*
|
|
139
|
+
* ```typescript
|
|
140
|
+
*
|
|
141
|
+
* class UserResolver {
|
|
142
|
+
* resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
143
|
+
* return new User();
|
|
144
|
+
* }
|
|
145
|
+
* }
|
|
146
|
+
*
|
|
147
|
+
* @http.resolveParameter(User, UserResolver)
|
|
148
|
+
* class MyController {
|
|
149
|
+
*
|
|
150
|
+
* @http.GET()
|
|
151
|
+
* myAction(user: User) {
|
|
152
|
+
* }
|
|
153
|
+
* }
|
|
154
|
+
*
|
|
155
|
+
* new App({providers: [UserResolver]}).run();
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
resolveParameter(classType: ClassType | string | any, resolver: ClassType<RouteParameterResolver>) {
|
|
159
|
+
this.t.resolverForToken.set(classType, resolver);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Adds a parameter resolver for parameters based on its name. Use .resolveParameter() for class-based resolving.
|
|
164
|
+
*
|
|
165
|
+
* ```typescript
|
|
166
|
+
*
|
|
167
|
+
* class UserResolver {
|
|
168
|
+
* resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
169
|
+
* return new User();
|
|
170
|
+
* }
|
|
171
|
+
* }
|
|
172
|
+
*
|
|
173
|
+
* @http.resolveParameterByName('user', UserResolver)
|
|
174
|
+
* class MyController {
|
|
175
|
+
*
|
|
176
|
+
* @http.GET()
|
|
177
|
+
* myAction(user: User) {
|
|
178
|
+
* }
|
|
179
|
+
* }
|
|
180
|
+
*
|
|
181
|
+
* new App({providers: [UserResolver]}).run();
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
resolveParameterByName(name: string, resolver: ClassType<RouteParameterResolver>) {
|
|
185
|
+
this.t.resolverForParameterName.set(name, resolver);
|
|
186
|
+
}
|
|
187
|
+
|
|
96
188
|
setAction(action: HttpAction) {
|
|
97
189
|
this.t.addAction(action);
|
|
98
190
|
}
|
|
99
191
|
}
|
|
100
192
|
|
|
101
|
-
export const httpClass: ClassDecoratorResult<typeof
|
|
193
|
+
export const httpClass: ClassDecoratorResult<typeof HttpControllerDecorator> = createClassDecoratorContext(HttpControllerDecorator);
|
|
194
|
+
|
|
195
|
+
export function getActions(target: ClassType): HttpAction[] {
|
|
196
|
+
const parent = Object.getPrototypeOf(target);
|
|
197
|
+
const results: HttpAction[] = parent ? getActions(parent) : [];
|
|
198
|
+
|
|
199
|
+
const config = httpClass._fetch(target);
|
|
200
|
+
if (config) {
|
|
201
|
+
for (const action of config.getActions()) {
|
|
202
|
+
const existing = results.findIndex(v => v.methodName === action.methodName);
|
|
203
|
+
if (existing !== -1) results.splice(existing, 1);
|
|
204
|
+
results.push(action);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return results;
|
|
209
|
+
}
|
|
102
210
|
|
|
103
211
|
export class HttpActionDecorator {
|
|
104
212
|
t = new HttpAction;
|
|
105
213
|
|
|
106
|
-
onDecorator(target: ClassType, property: string) {
|
|
214
|
+
onDecorator(target: ClassType, property: string | undefined, parameterIndexOrDescriptor?: any) {
|
|
215
|
+
if (!property) return;
|
|
216
|
+
if (target === Object) return;
|
|
107
217
|
this.t.methodName = property;
|
|
108
218
|
httpClass.setAction(this.t)(target);
|
|
109
219
|
}
|
|
@@ -112,14 +222,22 @@ export class HttpActionDecorator {
|
|
|
112
222
|
this.t.name = name;
|
|
113
223
|
}
|
|
114
224
|
|
|
115
|
-
setParameter(name: string, parameter: HttpActionParameter) {
|
|
116
|
-
this.t.parameters[name] = parameter;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
225
|
description(description: string) {
|
|
120
226
|
this.t.description = description;
|
|
121
227
|
}
|
|
122
228
|
|
|
229
|
+
serialization(options: SerializationOptions) {
|
|
230
|
+
this.t.serializationOptions = options;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
serializer(serializer: Serializer) {
|
|
234
|
+
this.t.serializer = serializer;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
middleware(...middlewares: HttpActionMiddleware[]) {
|
|
238
|
+
this.t.middlewares.push(...middlewares.map(v => isMiddlewareClassTypeOrFn(v) ? httpMiddleware.for(v) : v));
|
|
239
|
+
}
|
|
240
|
+
|
|
123
241
|
/**
|
|
124
242
|
* Allows to change the HttpAction object and composite multiple properties into one function.
|
|
125
243
|
*
|
|
@@ -154,7 +272,7 @@ export class HttpActionDecorator {
|
|
|
154
272
|
* assets() {}
|
|
155
273
|
* }
|
|
156
274
|
* ```
|
|
157
|
-
|
|
275
|
+
*/
|
|
158
276
|
data(name: string, value: any) {
|
|
159
277
|
this.t.data.set(name, value);
|
|
160
278
|
}
|
|
@@ -168,124 +286,144 @@ export class HttpActionDecorator {
|
|
|
168
286
|
}
|
|
169
287
|
|
|
170
288
|
GET(path: string = '') {
|
|
171
|
-
this.t.
|
|
172
|
-
this.t.path = path;
|
|
289
|
+
this.t.httpMethods.push('GET');
|
|
290
|
+
if (path) this.t.path = path;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
HEAD(path: string = '') {
|
|
294
|
+
this.t.httpMethods.push('HEAD');
|
|
295
|
+
if (path) this.t.path = path;
|
|
173
296
|
}
|
|
174
297
|
|
|
175
298
|
POST(path: string = '') {
|
|
176
|
-
this.t.
|
|
177
|
-
this.t.path = path;
|
|
299
|
+
this.t.httpMethods.push('POST');
|
|
300
|
+
if (path) this.t.path = path;
|
|
178
301
|
}
|
|
179
302
|
|
|
180
303
|
PUT(path: string = '') {
|
|
181
|
-
this.t.
|
|
182
|
-
this.t.path = path;
|
|
304
|
+
this.t.httpMethods.push('PUT');
|
|
305
|
+
if (path) this.t.path = path;
|
|
183
306
|
}
|
|
184
307
|
|
|
185
308
|
DELETE(path: string = '') {
|
|
186
|
-
this.t.
|
|
187
|
-
this.t.path = path;
|
|
309
|
+
this.t.httpMethods.push('DELETE');
|
|
310
|
+
if (path) this.t.path = path;
|
|
188
311
|
}
|
|
189
312
|
|
|
190
|
-
|
|
191
|
-
this.t.
|
|
192
|
-
this.t.path = path;
|
|
313
|
+
OPTIONS(path: string = '') {
|
|
314
|
+
this.t.httpMethods.push('OPTIONS');
|
|
315
|
+
if (path) this.t.path = path;
|
|
193
316
|
}
|
|
194
317
|
|
|
195
|
-
|
|
196
|
-
this.t.
|
|
318
|
+
TRACE(path: string = '') {
|
|
319
|
+
this.t.httpMethods.push('TRACE');
|
|
320
|
+
if (path) this.t.path = path;
|
|
197
321
|
}
|
|
198
322
|
|
|
199
|
-
|
|
200
|
-
this.t.
|
|
323
|
+
PATCH(path: string = '') {
|
|
324
|
+
this.t.httpMethods.push('PATCH');
|
|
325
|
+
if (path) this.t.path = path;
|
|
201
326
|
}
|
|
202
|
-
}
|
|
203
327
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
onDecorator(target: ClassType, propertyName?: string, parameterIndex?: number) {
|
|
208
|
-
if (!propertyName) throw new Error('@http action parameter decorator can only be used on method arguments.');
|
|
209
|
-
if (parameterIndex === undefined) throw new Error('@http action parameter decorator can only be used on method arguments.');
|
|
210
|
-
const schema = getClassSchema(target);
|
|
211
|
-
const property = schema.getMethodProperties(propertyName)[parameterIndex];
|
|
212
|
-
this.t.name = property.name;
|
|
213
|
-
if (this.t.typePath === undefined) {
|
|
214
|
-
this.t.typePath = property.name;
|
|
215
|
-
}
|
|
216
|
-
httpAction.setParameter(property.name, this.t)(target.prototype, propertyName);
|
|
328
|
+
ANY(path: string = '') {
|
|
329
|
+
this.t.httpMethods = [];
|
|
330
|
+
if (path) this.t.path = path;
|
|
217
331
|
}
|
|
218
332
|
|
|
219
333
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
334
|
+
* Adds additional information about what HTTP status codes are available in this route.
|
|
335
|
+
* You can add additionally a description and a response body type.
|
|
336
|
+
*
|
|
337
|
+
* The type is used for serialization for responses with the given statusCode.
|
|
338
|
+
*
|
|
339
|
+
* This information is available in Deepkit API console.
|
|
223
340
|
*
|
|
224
|
-
* @example
|
|
225
341
|
* ```typescript
|
|
226
|
-
*
|
|
227
|
-
*
|
|
342
|
+
*
|
|
343
|
+
* http.GET().response<boolean>(200, 'All ok')
|
|
344
|
+
*
|
|
345
|
+
* interface User {
|
|
346
|
+
* username: string;
|
|
228
347
|
* }
|
|
348
|
+
* http.GET().response<User>(200, 'User object')
|
|
229
349
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* myAction(@http.body() body: MyActionBody) {
|
|
233
|
-
* console.log('body', body.name);
|
|
234
|
-
* }
|
|
350
|
+
* interface HttpErrorMessage {
|
|
351
|
+
* error: string;
|
|
235
352
|
* }
|
|
353
|
+
* http.GET().response<HttpErrorMessage>(500, 'Error')
|
|
236
354
|
* ```
|
|
237
355
|
*/
|
|
238
|
-
|
|
239
|
-
this.t.type
|
|
240
|
-
this.t.typePath = ''; //root
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
query(path?: string) {
|
|
244
|
-
this.t.typePath = path; //undefined === propertyName
|
|
245
|
-
this.t.type = 'query';
|
|
356
|
+
response<T>(statusCode: number, description: string = '', type?: ReceiveType<T>) {
|
|
357
|
+
this.t.responses.push({ statusCode, description, type: type ? resolveReceiveType(type) : undefined });
|
|
246
358
|
}
|
|
247
359
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
360
|
+
/**
|
|
361
|
+
* Adds a parameter resolver for parameters based on the class type. Use .resolveParameterByName() for name-based resolving.
|
|
362
|
+
*
|
|
363
|
+
* ```typescript
|
|
364
|
+
*
|
|
365
|
+
* class UserResolver {
|
|
366
|
+
* resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
367
|
+
* return new User();
|
|
368
|
+
* }
|
|
369
|
+
* }
|
|
370
|
+
*
|
|
371
|
+
* class MyController {
|
|
372
|
+
* @http.GET()
|
|
373
|
+
* @http.resolveParameter(User, UserResolver)
|
|
374
|
+
* myAction(user: User) {
|
|
375
|
+
* }
|
|
376
|
+
* }
|
|
377
|
+
*
|
|
378
|
+
* new App({providers: [UserResolver]}).run();
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
resolveParameter(classType: ClassType | string | any, resolver: ClassType<RouteParameterResolver>) {
|
|
382
|
+
this.t.resolverForToken.set(classType, resolver);
|
|
251
383
|
}
|
|
252
384
|
|
|
253
385
|
/**
|
|
254
|
-
*
|
|
255
|
-
* and deserialized to the defined type.
|
|
256
|
-
* Define a `path` if you want to parse a subset of the query string only.
|
|
257
|
-
*
|
|
258
|
-
* Note: Make sure the defined parameter type has optional properties,
|
|
259
|
-
* otherwise it's always required to pass a query string.
|
|
386
|
+
* Adds a parameter resolver for parameters based on its name. Use .resolveParameter() for class-based resolving.
|
|
260
387
|
*
|
|
261
|
-
* @example
|
|
262
388
|
* ```typescript
|
|
263
|
-
*
|
|
264
|
-
*
|
|
389
|
+
*
|
|
390
|
+
* class UserResolver {
|
|
391
|
+
* resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
392
|
+
* return new User();
|
|
393
|
+
* }
|
|
265
394
|
* }
|
|
266
395
|
*
|
|
267
|
-
* class
|
|
268
|
-
* @http.GET(
|
|
269
|
-
*
|
|
270
|
-
*
|
|
396
|
+
* class MyController {
|
|
397
|
+
* @http.GET()
|
|
398
|
+
* @http.resolveParameterByName('user', UserResolver)
|
|
399
|
+
* myAction(user: User) {
|
|
271
400
|
* }
|
|
272
401
|
* }
|
|
273
402
|
*
|
|
274
|
-
*
|
|
275
|
-
* // -> /my-action?name=Peter
|
|
403
|
+
* new App({providers: [UserResolver]}).run();
|
|
276
404
|
* ```
|
|
277
|
-
*
|
|
278
405
|
*/
|
|
279
|
-
|
|
280
|
-
this.t.
|
|
281
|
-
this.t.type = 'query';
|
|
406
|
+
resolveParameterByName(name: string, resolver: ClassType<RouteParameterResolver>) {
|
|
407
|
+
this.t.resolverForParameterName.set(name, resolver);
|
|
282
408
|
}
|
|
283
409
|
}
|
|
284
410
|
|
|
285
|
-
|
|
411
|
+
//this workaround is necessary since generic functions (necessary for response<T>) are lost during a mapped type and changed ReturnType
|
|
412
|
+
type HttpActionFluidDecorator<T, D extends Function> = {
|
|
413
|
+
[name in keyof T]: name extends 'response' ? <T2>(statusCode: number, description?: string, type?: ReceiveType<T2>) => D & HttpActionFluidDecorator<T, D>
|
|
414
|
+
: T[name] extends (...args: infer K) => any ? (...args: K) => D & HttpActionFluidDecorator<T, D>
|
|
415
|
+
: D & HttpActionFluidDecorator<T, D> & { _data: ExtractApiDataType<T> };
|
|
416
|
+
};
|
|
417
|
+
type HttpActionPropertyDecoratorResult =
|
|
418
|
+
HttpActionFluidDecorator<ExtractClass<typeof HttpActionDecorator>, PropertyDecoratorFn>
|
|
419
|
+
& DecoratorAndFetchSignature<typeof HttpActionDecorator, PropertyDecoratorFn>;
|
|
420
|
+
|
|
421
|
+
export const httpAction: HttpActionPropertyDecoratorResult = createPropertyDecoratorContext(HttpActionDecorator);
|
|
286
422
|
|
|
287
|
-
|
|
423
|
+
//this workaround is necessary since generic functions are lost during a mapped type and changed ReturnType
|
|
424
|
+
type HttpMerge<U> = { [K in keyof U]: K extends 'response' ? <T2>(statusCode: number, description?: string, type?: ReceiveType<T2>) => PropertyDecoratorFn & U : U[K] extends ((...a: infer A) => infer R) ? R extends DualDecorator ? (...a: A) => PropertyDecoratorFn & R & U : (...a: A) => R : never };
|
|
425
|
+
type MergedHttp<T extends any[]> = HttpMerge<Omit<UnionToIntersection<T[number]>, '_fetch' | 't'>>
|
|
288
426
|
|
|
289
|
-
export
|
|
427
|
+
export type HttpDecorator = PropertyDecoratorFn & HttpActionFluidDecorator<HttpActionDecorator, PropertyDecoratorFn>;
|
|
290
428
|
|
|
291
|
-
export const http = mergeDecorator(httpClass, httpAction,
|
|
429
|
+
export const http: MergedHttp<[typeof httpClass, typeof httpAction]> = mergeDecorator(httpClass, httpAction) as any as MergedHttp<[typeof httpClass, typeof httpAction]>;
|