@deepkit/http 1.0.1-alpha.70 → 1.0.1-alpha.73
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/dist/cjs/src/decorator.d.ts +8 -6
- package/dist/cjs/src/decorator.js +49 -12
- package/dist/cjs/src/decorator.js.map +1 -1
- package/dist/cjs/src/filter.d.ts +3 -3
- package/dist/cjs/src/filter.js +3 -3
- package/dist/cjs/src/filter.js.map +1 -1
- package/dist/cjs/src/http.d.ts +49 -11
- package/dist/cjs/src/http.js +124 -38
- package/dist/cjs/src/http.js.map +1 -1
- package/dist/cjs/src/kernel.d.ts +3 -3
- package/dist/cjs/src/kernel.js +1 -1
- package/dist/cjs/src/kernel.js.map +1 -1
- package/dist/cjs/src/model.d.ts +11 -3
- package/dist/cjs/src/model.js +58 -26
- package/dist/cjs/src/model.js.map +1 -1
- package/dist/cjs/src/module.js +5 -3
- package/dist/cjs/src/module.js.map +1 -1
- package/dist/cjs/src/router.d.ts +84 -11
- package/dist/cjs/src/router.js +280 -94
- package/dist/cjs/src/router.js.map +1 -1
- package/dist/cjs/src/static-serving.js +15 -8
- package/dist/cjs/src/static-serving.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/src/decorator.d.ts +8 -6
- package/dist/esm/src/decorator.js +47 -11
- package/dist/esm/src/decorator.js.map +1 -1
- package/dist/esm/src/filter.d.ts +3 -3
- package/dist/esm/src/filter.js +4 -4
- package/dist/esm/src/filter.js.map +1 -1
- package/dist/esm/src/http.d.ts +49 -11
- package/dist/esm/src/http.js +111 -38
- package/dist/esm/src/http.js.map +1 -1
- package/dist/esm/src/kernel.d.ts +3 -3
- package/dist/esm/src/kernel.js +2 -2
- package/dist/esm/src/kernel.js.map +1 -1
- package/dist/esm/src/model.d.ts +11 -3
- package/dist/esm/src/model.js +47 -15
- package/dist/esm/src/model.js.map +1 -1
- package/dist/esm/src/module.js +6 -4
- package/dist/esm/src/module.js.map +1 -1
- package/dist/esm/src/router.d.ts +84 -11
- package/dist/esm/src/router.js +278 -94
- package/dist/esm/src/router.js.map +1 -1
- package/dist/esm/src/static-serving.js +16 -9
- package/dist/esm/src/static-serving.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +17 -14
- package/src/decorator.ts +9 -6
- package/src/filter.ts +4 -4
- package/src/http.ts +83 -15
- package/src/kernel.ts +2 -2
- package/src/model.ts +35 -6
- package/src/module.ts +5 -3
- package/src/router.ts +286 -73
- package/src/static-serving.ts +6 -3
- package/coverage/clover.xml +0 -1086
- package/coverage/coverage-final.json +0 -12
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -79
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -126
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -170
- package/coverage/lcov-report/src/controllers.ts.html +0 -113
- package/coverage/lcov-report/src/decorator.ts.html +0 -1280
- package/coverage/lcov-report/src/filter.ts.html +0 -734
- package/coverage/lcov-report/src/http.ts.html +0 -2192
- package/coverage/lcov-report/src/index.html +0 -246
- package/coverage/lcov-report/src/kernel.ts.html +0 -260
- package/coverage/lcov-report/src/middleware.ts.html +0 -428
- package/coverage/lcov-report/src/model.ts.html +0 -937
- package/coverage/lcov-report/src/module.config.ts.html +0 -89
- package/coverage/lcov-report/src/module.ts.html +0 -245
- package/coverage/lcov-report/src/router.ts.html +0 -2318
- package/coverage/lcov-report/tests/index.html +0 -111
- package/coverage/lcov-report/tests/utils.ts.html +0 -176
- package/coverage/lcov.info +0 -2225
- package/dist/cjs/tests/filter.spec.d.ts +0 -1
- package/dist/cjs/tests/filter.spec.js +0 -251
- package/dist/cjs/tests/filter.spec.js.map +0 -1
- package/dist/cjs/tests/middleware.spec.d.ts +0 -1
- package/dist/cjs/tests/middleware.spec.js +0 -471
- package/dist/cjs/tests/middleware.spec.js.map +0 -1
- package/dist/cjs/tests/model.spec.d.ts +0 -1
- package/dist/cjs/tests/model.spec.js +0 -23
- package/dist/cjs/tests/model.spec.js.map +0 -1
- package/dist/cjs/tests/module.spec.d.ts +0 -1
- package/dist/cjs/tests/module.spec.js +0 -46
- package/dist/cjs/tests/module.spec.js.map +0 -1
- package/dist/cjs/tests/router.spec.d.ts +0 -1
- package/dist/cjs/tests/router.spec.js +0 -987
- package/dist/cjs/tests/router.spec.js.map +0 -1
- package/dist/cjs/tests/utils.d.ts +0 -8
- package/dist/cjs/tests/utils.js +0 -30
- package/dist/cjs/tests/utils.js.map +0 -1
- package/dist/esm/tests/filter.spec.d.ts +0 -1
- package/dist/esm/tests/filter.spec.js +0 -249
- package/dist/esm/tests/filter.spec.js.map +0 -1
- package/dist/esm/tests/middleware.spec.d.ts +0 -1
- package/dist/esm/tests/middleware.spec.js +0 -469
- package/dist/esm/tests/middleware.spec.js.map +0 -1
- package/dist/esm/tests/model.spec.d.ts +0 -1
- package/dist/esm/tests/model.spec.js +0 -21
- package/dist/esm/tests/model.spec.js.map +0 -1
- package/dist/esm/tests/module.spec.d.ts +0 -1
- package/dist/esm/tests/module.spec.js +0 -44
- package/dist/esm/tests/module.spec.js.map +0 -1
- package/dist/esm/tests/router.spec.d.ts +0 -1
- package/dist/esm/tests/router.spec.js +0 -985
- package/dist/esm/tests/router.spec.js.map +0 -1
- package/dist/esm/tests/utils.d.ts +0 -8
- package/dist/esm/tests/utils.js +0 -26
- package/dist/esm/tests/utils.js.map +0 -1
- package/tests/filter.spec.ts +0 -181
- package/tests/middleware.spec.ts +0 -440
- package/tests/model.spec.ts +0 -26
- package/tests/module.spec.ts +0 -32
- package/tests/router.spec.ts +0 -781
- package/tests/utils.ts +0 -32
package/tests/router.spec.ts
DELETED
|
@@ -1,781 +0,0 @@
|
|
|
1
|
-
import { expect, test } from '@jest/globals';
|
|
2
|
-
import { dotToUrlPath, RouteParameterResolverContext, Router, UploadedFile } from '../src/router';
|
|
3
|
-
import { http, httpClass } from '../src/decorator';
|
|
4
|
-
import { HttpBadRequestError, httpWorkflow, JSONResponse } from '../src/http';
|
|
5
|
-
import { eventDispatcher } from '@deepkit/event';
|
|
6
|
-
import { HttpBody, HttpBodyValidation, HttpQueries, HttpQuery, HttpRegExp, HttpRequest } from '../src/model';
|
|
7
|
-
import { getClassName, sleep } from '@deepkit/core';
|
|
8
|
-
import { createHttpKernel } from './utils';
|
|
9
|
-
import { Group, MinLength } from '@deepkit/type';
|
|
10
|
-
|
|
11
|
-
test('router', async () => {
|
|
12
|
-
class Controller {
|
|
13
|
-
@http.GET()
|
|
14
|
-
helloWorld() {
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
@http.GET(':name')
|
|
18
|
-
hello(name: string) {
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@http.GET('/user/:id/static')
|
|
22
|
-
userStatic(id: string) {
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@http.GET('/user2/:id/static/:id2')
|
|
26
|
-
userStatic2(id: string, id2: string) {
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@http.ANY('/any')
|
|
30
|
-
any() {
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const router = Router.forControllers([Controller]);
|
|
35
|
-
|
|
36
|
-
expect((await router.resolve('GET', '/'))?.routeConfig.action).toMatchObject({ controller: Controller, methodName: 'helloWorld' });
|
|
37
|
-
expect((await router.resolve('GET', '/peter'))?.routeConfig.action).toMatchObject({ controller: Controller, methodName: 'hello' });
|
|
38
|
-
expect((await router.resolve('GET', '/peter'))?.parameters!(undefined as any)).toEqual(['peter']);
|
|
39
|
-
|
|
40
|
-
const userStatic = await router.resolve('GET', '/user/1233/static');
|
|
41
|
-
expect(userStatic?.routeConfig.action).toMatchObject({ controller: Controller, methodName: 'userStatic' });
|
|
42
|
-
expect(userStatic?.parameters!(undefined as any)).toEqual(['1233']);
|
|
43
|
-
|
|
44
|
-
const userStatic2 = await router.resolve('GET', '/user2/1233/static/123');
|
|
45
|
-
expect(userStatic2?.routeConfig.action).toMatchObject({ controller: Controller, methodName: 'userStatic2' });
|
|
46
|
-
expect(userStatic2?.parameters!(undefined as any)).toEqual(['1233', '123']);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('any', async () => {
|
|
50
|
-
class Controller {
|
|
51
|
-
@http.ANY('/any')
|
|
52
|
-
any() {
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const router = Router.forControllers([Controller]);
|
|
57
|
-
|
|
58
|
-
expect((await router.resolve('GET', '/any'))!.routeConfig.action.methodName).toEqual('any');
|
|
59
|
-
expect((await router.resolve('POST', '/any'))!.routeConfig.action.methodName).toEqual('any');
|
|
60
|
-
expect((await router.resolve('OPTIONS', '/any'))!.routeConfig.action.methodName).toEqual('any');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('router parameters', async () => {
|
|
64
|
-
class Controller {
|
|
65
|
-
@http.GET('/user/:name')
|
|
66
|
-
string(name: string) {
|
|
67
|
-
return new JSONResponse(name);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@http.GET('/user-id/:id')
|
|
71
|
-
number(id: number) {
|
|
72
|
-
return new JSONResponse(id);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@http.GET('/boolean/:yes')
|
|
76
|
-
boolean(yes: boolean) {
|
|
77
|
-
return new JSONResponse(yes);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
@http.GET(':path')
|
|
81
|
-
any(path: HttpRegExp<string, '.*'>) {
|
|
82
|
-
return new JSONResponse(path);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const router = Router.forControllers([Controller]);
|
|
87
|
-
expect((await router.resolve('GET', '/user/peter'))?.routeConfig.action).toMatchObject({ controller: Controller, methodName: 'string' });
|
|
88
|
-
|
|
89
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
90
|
-
|
|
91
|
-
expect((await httpKernel.request(HttpRequest.GET('/user/peter'))).json).toBe('peter');
|
|
92
|
-
expect((await httpKernel.request(HttpRequest.GET('/user-id/123'))).json).toBe(123);
|
|
93
|
-
expect((await httpKernel.request(HttpRequest.GET('/user-id/asd'))).json).toMatchObject({ message: 'Validation error:\nid(type): Cannot convert asd to number' });
|
|
94
|
-
expect((await httpKernel.request(HttpRequest.GET('/boolean/1'))).json).toBe(true);
|
|
95
|
-
expect((await httpKernel.request(HttpRequest.GET('/boolean/false'))).json).toBe(false);
|
|
96
|
-
|
|
97
|
-
expect((await httpKernel.request(HttpRequest.GET('/any'))).json).toBe('any');
|
|
98
|
-
expect((await httpKernel.request(HttpRequest.GET('/any/path'))).json).toBe('any/path');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
test('router HttpRequest', async () => {
|
|
102
|
-
class Controller {
|
|
103
|
-
@http.GET(':path')
|
|
104
|
-
anyReq(req: HttpRequest, path: HttpRegExp<string, '.*'>) {
|
|
105
|
-
return [req.url, path];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
110
|
-
|
|
111
|
-
expect((await httpKernel.request(HttpRequest.GET('/req/any/path'))).json).toEqual(['/req/any/path', 'req/any/path']);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('router parameter resolver by class', async () => {
|
|
115
|
-
class User {
|
|
116
|
-
constructor(public username: string) {
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
class Group {
|
|
121
|
-
constructor(public name: string) {
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
class UserResolver {
|
|
126
|
-
resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
127
|
-
const value = context.value || context.parameters.username;
|
|
128
|
-
if (!value) throw new Error('No value specified');
|
|
129
|
-
return new User(value);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
class GroupResolver {
|
|
134
|
-
resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
135
|
-
if (!context.value) throw new Error('No value specified');
|
|
136
|
-
return new Group(context.value);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
@http.resolveParameter(User, UserResolver)
|
|
141
|
-
class Controller {
|
|
142
|
-
@http.GET('user/:username')
|
|
143
|
-
route1(user: User) {
|
|
144
|
-
return [user.username];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
@http.GET('invalid')
|
|
148
|
-
route2(user: User) {
|
|
149
|
-
return [user.username];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@http.GET('user/:user/group/:group').resolveParameter(Group, GroupResolver)
|
|
153
|
-
route3(user: User, group: Group) {
|
|
154
|
-
return [user.username, group.name];
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const data = httpClass._fetch(Controller)!;
|
|
159
|
-
expect(data.getActions().size).toBe(3);
|
|
160
|
-
expect(data.resolverForToken.get(User)).toBe(UserResolver);
|
|
161
|
-
expect(data.resolverForToken.get(User)).toBe(UserResolver);
|
|
162
|
-
expect(data.getAction('route3').resolverForToken.get(Group)).toBe(GroupResolver);
|
|
163
|
-
|
|
164
|
-
const httpKernel = createHttpKernel([Controller], [UserResolver, GroupResolver]);
|
|
165
|
-
|
|
166
|
-
expect((await httpKernel.request(HttpRequest.GET('/user/peter'))).json).toEqual(['peter']);
|
|
167
|
-
expect((await httpKernel.request(HttpRequest.GET('/user/peter/group/a'))).json).toEqual(['peter', 'a']);
|
|
168
|
-
expect((await httpKernel.request(HttpRequest.GET('/invalid'))).bodyString).toEqual('Internal error');
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test('router parameter resolver by name', async () => {
|
|
172
|
-
class User {
|
|
173
|
-
constructor(public username: string) {
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
class Group {
|
|
178
|
-
constructor(public name: string) {
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
class UserResolver {
|
|
183
|
-
resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
184
|
-
const value = context.value || context.parameters.username;
|
|
185
|
-
if (!value) {
|
|
186
|
-
throw new Error('No value specified');
|
|
187
|
-
}
|
|
188
|
-
return new User(value);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
class GroupResolver {
|
|
193
|
-
resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
194
|
-
if (!context.value) throw new Error('No value specified');
|
|
195
|
-
return new Group(context.value);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
class MyAuth {
|
|
200
|
-
constructor(public name: string) {
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
class AuthResolver {
|
|
205
|
-
resolve(context: RouteParameterResolverContext): any | Promise<any> {
|
|
206
|
-
return new MyAuth('auth');
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
@http.resolveParameterByName('user', UserResolver)
|
|
211
|
-
class Controller {
|
|
212
|
-
@http.GET('user/:username')
|
|
213
|
-
route1(user: User) {
|
|
214
|
-
return [user.username];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
@http.GET('invalid')
|
|
218
|
-
route2(user: User) {
|
|
219
|
-
return [user.username];
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
@http.GET('user/:user/group/:group').resolveParameterByName('group', GroupResolver)
|
|
223
|
-
route3(user: User, group: Group) {
|
|
224
|
-
return [user.username, group.name];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
@http.GET('nonClass').resolveParameterByName('auth', AuthResolver)
|
|
228
|
-
nonClass(auth: any) {
|
|
229
|
-
return [auth.name, getClassName(auth)];
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const data = httpClass._fetch(Controller)!;
|
|
234
|
-
expect(data.getActions().size).toBe(4);
|
|
235
|
-
expect(data.resolverForParameterName.get('user')).toBe(UserResolver);
|
|
236
|
-
expect(data.getAction('route3').resolverForParameterName.get('group')).toBe(GroupResolver);
|
|
237
|
-
|
|
238
|
-
const httpKernel = createHttpKernel([Controller], [UserResolver, GroupResolver, AuthResolver]);
|
|
239
|
-
|
|
240
|
-
expect((await httpKernel.request(HttpRequest.GET('/user/peter'))).json).toEqual(['peter']);
|
|
241
|
-
expect((await httpKernel.request(HttpRequest.GET('/user/peter/group/a'))).json).toEqual(['peter', 'a']);
|
|
242
|
-
expect((await httpKernel.request(HttpRequest.GET('/invalid'))).bodyString).toEqual('Internal error');
|
|
243
|
-
expect((await httpKernel.request(HttpRequest.GET('/nonClass'))).json).toEqual(['auth', 'MyAuth']);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
test('router body class', async () => {
|
|
247
|
-
class Body {
|
|
248
|
-
username!: string;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
class Controller {
|
|
252
|
-
@http.POST()
|
|
253
|
-
anyReq(body: HttpBody<Body>, req: HttpRequest) {
|
|
254
|
-
return [body.username, body instanceof Body, req.url];
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
259
|
-
|
|
260
|
-
expect((await httpKernel.request(HttpRequest.POST('/').json({ username: 'Peter' }))).json).toEqual(['Peter', true, '/']);
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
test('router body is safe for simultaneous requests', async () => {
|
|
264
|
-
class Body {
|
|
265
|
-
username!: string;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
class Controller {
|
|
269
|
-
@http.POST()
|
|
270
|
-
anyReq(body: HttpBody<Body>, req: HttpRequest) {
|
|
271
|
-
return [body.username, body instanceof Body, req.url];
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
276
|
-
|
|
277
|
-
const makeReq = () => httpKernel.request(HttpRequest.POST('/').json({ username: 'Peter' }));
|
|
278
|
-
|
|
279
|
-
const results = await Promise.all([...new Array(100)].map(() => makeReq().then(res => res.json)));
|
|
280
|
-
|
|
281
|
-
expect(results).toEqual(
|
|
282
|
-
results.map(() => ['Peter', true, '/']),
|
|
283
|
-
)
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test('router body interface', async () => {
|
|
287
|
-
interface Body {
|
|
288
|
-
username: string;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
class Controller {
|
|
292
|
-
@http.POST()
|
|
293
|
-
anyReq(body: HttpBody<Body>, req: HttpRequest) {
|
|
294
|
-
return [body.username, typeof body.username, req.url];
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
299
|
-
|
|
300
|
-
expect((await httpKernel.request(HttpRequest.POST('/').json({ username: 'Peter' }))).json).toEqual(['Peter', 'string', '/']);
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
test('router body double', async () => {
|
|
304
|
-
class Body {
|
|
305
|
-
username!: string;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
class Controller {
|
|
309
|
-
@http.POST()
|
|
310
|
-
anyReq(body: HttpBody<Body>, body2: HttpBody<Body>, req: HttpRequest) {
|
|
311
|
-
return [body2.username, body2 instanceof Body && body instanceof Body, req.url];
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const httpData = httpClass._fetch(Controller);
|
|
316
|
-
if (!httpData) throw new Error('httpClass undefined');
|
|
317
|
-
const action = [...httpData.getActions()][0];
|
|
318
|
-
expect(action.methodName).toBe('anyReq');
|
|
319
|
-
expect(action.httpMethods).toEqual(['POST']);
|
|
320
|
-
|
|
321
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
322
|
-
|
|
323
|
-
expect((await httpKernel.request(HttpRequest.POST('/').json({ username: 'Peter' }))).json).toEqual(['Peter', true, '/']);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
test('router groups', async () => {
|
|
327
|
-
{
|
|
328
|
-
class Controller {
|
|
329
|
-
@http.GET('a').group('a')
|
|
330
|
-
a() {
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
@http.GET('b')
|
|
334
|
-
b() {
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
@http.GET('c').group('c')
|
|
338
|
-
c() {
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const httpData = httpClass._fetch(Controller);
|
|
343
|
-
if (!httpData) throw new Error('httpClass undefined');
|
|
344
|
-
expect(httpData.getAction('a').groups).toEqual(['a']);
|
|
345
|
-
expect(httpData.getAction('b').groups).toEqual([]);
|
|
346
|
-
expect(httpData.getAction('c').groups).toEqual(['c']);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
{
|
|
350
|
-
@http.group('all')
|
|
351
|
-
class Controller {
|
|
352
|
-
@http.GET('a').group('a')
|
|
353
|
-
a() {
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
@http.GET('b')
|
|
357
|
-
b() {
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
@http.GET('c').group('c')
|
|
361
|
-
c() {
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const httpData = httpClass._fetch(Controller);
|
|
366
|
-
if (!httpData) throw new Error('httpClass undefined');
|
|
367
|
-
expect(httpData.getAction('a').groups).toEqual(['a', 'all']);
|
|
368
|
-
expect(httpData.getAction('b').groups).toEqual(['all']);
|
|
369
|
-
expect(httpData.getAction('c').groups).toEqual(['c', 'all']);
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
test('router query', async () => {
|
|
374
|
-
class Controller {
|
|
375
|
-
@http.GET('my-action')
|
|
376
|
-
anyReq(test?: HttpQuery<number>) {
|
|
377
|
-
return test;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const httpData = httpClass._fetch(Controller);
|
|
382
|
-
if (!httpData) throw new Error('httpClass undefined');
|
|
383
|
-
const action = [...httpData.getActions()][0];
|
|
384
|
-
expect(action.methodName).toBe('anyReq');
|
|
385
|
-
expect(action.httpMethods).toEqual(['GET']);
|
|
386
|
-
|
|
387
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
388
|
-
|
|
389
|
-
expect((await httpKernel.request(HttpRequest.GET('/my-action?test=123'))).json).toEqual(123);
|
|
390
|
-
expect((await httpKernel.request(HttpRequest.GET('/my-action'))).bodyString).toEqual('');
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
test('router query all', async () => {
|
|
394
|
-
class AnyReqQuery {
|
|
395
|
-
test?: string;
|
|
396
|
-
filter?: string;
|
|
397
|
-
page?: number;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
class Controller {
|
|
401
|
-
@http.GET('my-action')
|
|
402
|
-
anyReq(anyReqQuery: HttpQueries<AnyReqQuery>) {
|
|
403
|
-
return anyReqQuery;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
408
|
-
|
|
409
|
-
expect((await httpKernel.request(HttpRequest.GET('/my-action?test=123'))).json).toEqual({ test: '123' });
|
|
410
|
-
expect((await httpKernel.request(HttpRequest.GET('/my-action'))).json).toEqual({});
|
|
411
|
-
expect((await httpKernel.request(HttpRequest.GET('/my-action?filter=page&page=5'))).json).toEqual({ filter: 'page', page: 5 });
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
test('serializer options', async () => {
|
|
415
|
-
class User {
|
|
416
|
-
username!: string;
|
|
417
|
-
password!: string & Group<'sensitive'>;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
class Controller {
|
|
421
|
-
@http.GET().serialization({ groupsExclude: ['sensitive'] })
|
|
422
|
-
anyReq(): User {
|
|
423
|
-
return { username: 'Peter', password: 'secret' };
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
428
|
-
|
|
429
|
-
expect((await httpKernel.request(HttpRequest.GET('/'))).json).toEqual({ username: 'Peter' });
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
test('hook after serializer', async () => {
|
|
433
|
-
class User {
|
|
434
|
-
username!: string;
|
|
435
|
-
password!: string & Group<'sensitive'>;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
class Controller {
|
|
439
|
-
@http.GET().serialization({ groupsExclude: ['sensitive'] })
|
|
440
|
-
async anyReq(): Promise<User> {
|
|
441
|
-
await sleep(0.1);
|
|
442
|
-
return { username: 'Peter', password: 'secret' };
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
class Listener {
|
|
447
|
-
@eventDispatcher.listen(httpWorkflow.onResponse)
|
|
448
|
-
onResponse(event: typeof httpWorkflow.onResponse.event) {
|
|
449
|
-
event.result = { processingTime: event.controllerActionTime, data: event.result };
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const httpKernel = createHttpKernel([Controller], [], [Listener]);
|
|
454
|
-
|
|
455
|
-
const result = (await httpKernel.request(HttpRequest.GET('/'))).json;
|
|
456
|
-
expect(result.data).toEqual({ username: 'Peter' });
|
|
457
|
-
expect(result.processingTime).toBeGreaterThanOrEqual(99);
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
test('invalid route definition', async () => {
|
|
461
|
-
class Controller {
|
|
462
|
-
@http.GET()
|
|
463
|
-
doIt(user: any) {
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
468
|
-
expect((await httpKernel.request(HttpRequest.GET('/'))).bodyString).toEqual('Internal error');
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
test('inject request storage ClassType', async () => {
|
|
472
|
-
class User {
|
|
473
|
-
constructor(public username: string) {
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
class Controller {
|
|
478
|
-
@http.GET()
|
|
479
|
-
doIt(user: User) {
|
|
480
|
-
return { isUser: user instanceof User, username: user.username };
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
@http.GET('optional')
|
|
484
|
-
doItOptional(user?: User) {
|
|
485
|
-
return { isUser: user instanceof User };
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
class Listener {
|
|
490
|
-
@eventDispatcher.listen(httpWorkflow.onAuth)
|
|
491
|
-
onAuth(event: typeof httpWorkflow.onAuth.event) {
|
|
492
|
-
if (event.request.headers.authorization === 'yes') {
|
|
493
|
-
event.request.store.user = new User('bar');
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
const httpKernel = createHttpKernel([Controller], [
|
|
499
|
-
{
|
|
500
|
-
provide: User, scope: 'http', useFactory(request: HttpRequest) {
|
|
501
|
-
return request.store.user;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
], [Listener]);
|
|
505
|
-
|
|
506
|
-
expect((await httpKernel.request(HttpRequest.GET('/').headers({ authorization: 'yes' }))).json).toEqual({ isUser: true, username: 'bar' });
|
|
507
|
-
expect((await httpKernel.request(HttpRequest.GET('/').headers({ authorization: 'no' }))).bodyString).toEqual('Internal error');
|
|
508
|
-
|
|
509
|
-
expect((await httpKernel.request(HttpRequest.GET('/optional').headers({ authorization: 'no' }))).json).toEqual({ isUser: false });
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
test('custom request handling', async () => {
|
|
513
|
-
class Listener {
|
|
514
|
-
@eventDispatcher.listen(httpWorkflow.onRouteNotFound)
|
|
515
|
-
onRouteNotFound(event: typeof httpWorkflow.onRouteNotFound.event) {
|
|
516
|
-
//CORS requirement for example
|
|
517
|
-
if (event.request.method === 'OPTIONS') event.send(new JSONResponse(true, 200));
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
const httpKernel = createHttpKernel([], [], [Listener]);
|
|
522
|
-
expect((await httpKernel.request(HttpRequest.OPTIONS('/'))).json).toBe(true);
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
test('race condition', async () => {
|
|
526
|
-
let call = 0;
|
|
527
|
-
|
|
528
|
-
class Listener {
|
|
529
|
-
@eventDispatcher.listen(httpWorkflow.onAuth)
|
|
530
|
-
async onRouteNotFound(event: typeof httpWorkflow.onRouteNotFound.event) {
|
|
531
|
-
if (call === 0) {
|
|
532
|
-
await sleep(0.1);
|
|
533
|
-
}
|
|
534
|
-
call++;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
class Controller {
|
|
539
|
-
@http.GET('/one/:param1')
|
|
540
|
-
one(param1: string) {
|
|
541
|
-
return param1;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
@http.GET('/second/:param2')
|
|
545
|
-
second(param2: string) {
|
|
546
|
-
return param2;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
const httpKernel = createHttpKernel([Controller], [], [Listener]);
|
|
552
|
-
|
|
553
|
-
const [a, b] = await Promise.all([
|
|
554
|
-
httpKernel.request(HttpRequest.GET('/one/a')),
|
|
555
|
-
httpKernel.request(HttpRequest.GET('/second/b')),
|
|
556
|
-
]);
|
|
557
|
-
expect(a.json).toBe('a');
|
|
558
|
-
expect(b.json).toBe('b');
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
test('multiple methods', async () => {
|
|
562
|
-
class Controller {
|
|
563
|
-
@http.GET('/one').POST()
|
|
564
|
-
one() {
|
|
565
|
-
return true;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const httpKernel = createHttpKernel([Controller], [], []);
|
|
570
|
-
|
|
571
|
-
expect((await httpKernel.request(HttpRequest.GET('/one'))).json).toBe(true);
|
|
572
|
-
expect((await httpKernel.request(HttpRequest.POST('/one'))).json).toBe(true);
|
|
573
|
-
expect((await httpKernel.request(HttpRequest.PATCH('/one'))).bodyString).toBe('Not found');
|
|
574
|
-
expect((await httpKernel.request(HttpRequest.PUT('/one'))).bodyString).toBe('Not found');
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
test('promise serializer', async () => {
|
|
578
|
-
class Controller {
|
|
579
|
-
@http.GET('1')
|
|
580
|
-
async anyReq1() {
|
|
581
|
-
return 'test';
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
@http.GET('2')
|
|
585
|
-
async anyReq2(): Promise<string> {
|
|
586
|
-
return 1 as any;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
591
|
-
|
|
592
|
-
expect((await httpKernel.request(HttpRequest.GET('/1'))).json).toBe('test');
|
|
593
|
-
expect((await httpKernel.request(HttpRequest.GET('/2'))).json).toBe('1');
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
test('unions', async () => {
|
|
597
|
-
class Controller {
|
|
598
|
-
@http.GET('/list')
|
|
599
|
-
list(page: HttpQuery<number | boolean>) {
|
|
600
|
-
return page;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
605
|
-
|
|
606
|
-
expect((await httpKernel.request(HttpRequest.GET('/list?page=0'))).json).toEqual(0);
|
|
607
|
-
expect((await httpKernel.request(HttpRequest.GET('/list?page=1'))).json).toEqual(1);
|
|
608
|
-
expect((await httpKernel.request(HttpRequest.GET('/list?page=2222'))).json).toEqual(2222);
|
|
609
|
-
expect((await httpKernel.request(HttpRequest.GET('/list?page=false'))).json).toEqual(false);
|
|
610
|
-
expect((await httpKernel.request(HttpRequest.GET('/list?page=true'))).json).toEqual(true);
|
|
611
|
-
|
|
612
|
-
expect((await httpKernel.request(HttpRequest.GET('/list?page=asdasdc'))).json).toMatchObject({
|
|
613
|
-
'errors': [
|
|
614
|
-
{
|
|
615
|
-
'code': 'type',
|
|
616
|
-
'message': 'No value given',
|
|
617
|
-
'path': 'page'
|
|
618
|
-
}
|
|
619
|
-
],
|
|
620
|
-
});
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
test('router dotToUrlPath', () => {
|
|
624
|
-
expect(dotToUrlPath('peter')).toBe('peter');
|
|
625
|
-
expect(dotToUrlPath('foo.bar')).toBe('foo[bar]');
|
|
626
|
-
expect(dotToUrlPath('foo.bar.deep')).toBe('foo[bar][deep]');
|
|
627
|
-
expect(dotToUrlPath('foo.bar.deep.very')).toBe('foo[bar][deep][very]');
|
|
628
|
-
});
|
|
629
|
-
|
|
630
|
-
test('router url resolve', async () => {
|
|
631
|
-
class AnyReqQuery {
|
|
632
|
-
test?: string;
|
|
633
|
-
filter?: string;
|
|
634
|
-
page?: number;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
class Controller {
|
|
638
|
-
@http.GET('').name('first')
|
|
639
|
-
first() {
|
|
640
|
-
return '';
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
@http.GET(':peter').name('second')
|
|
644
|
-
second(peter: string) {
|
|
645
|
-
return '';
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
@http.GET('').name('secondQuery')
|
|
649
|
-
secondQuery(peter: HttpQuery<string>) {
|
|
650
|
-
return '';
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
@http.GET('').name('secondQuery2')
|
|
654
|
-
secondQuery2(peter: HttpQuery<string, { name: 'changed' }>) {
|
|
655
|
-
return '';
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
@http.GET('third').name('third')
|
|
659
|
-
third(params: HttpQueries<AnyReqQuery>) {
|
|
660
|
-
return params;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
@http.GET('third2').name('third2')
|
|
664
|
-
third2(params: HttpQueries<AnyReqQuery, { name: 'deep' }>) {
|
|
665
|
-
return params;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
const router = Router.forControllers([Controller]);
|
|
670
|
-
|
|
671
|
-
expect(router.resolveUrl('first')).toBe('/');
|
|
672
|
-
expect(router.resolveUrl('second', { peter: 'foo' })).toBe('/foo');
|
|
673
|
-
expect(router.resolveUrl('secondQuery', { peter: 'foo' })).toBe('/?peter=foo');
|
|
674
|
-
expect(router.resolveUrl('secondQuery2', { peter: 'foo' })).toBe('/?changed=foo');
|
|
675
|
-
expect(router.resolveUrl('third', {})).toBe('/third');
|
|
676
|
-
expect(router.resolveUrl('third', { params: { test: 123 } })).toBe('/third?test=123');
|
|
677
|
-
expect(router.resolveUrl('third', { params: { test: 123, filter: 'peter' } })).toBe('/third?test=123&filter=peter');
|
|
678
|
-
|
|
679
|
-
expect(router.resolveUrl('third2', {})).toBe('/third2');
|
|
680
|
-
expect(router.resolveUrl('third2', { params: { test: 123 } })).toBe('/third2?deep[test]=123');
|
|
681
|
-
expect(router.resolveUrl('third2', { params: { test: 123, filter: 'peter' } })).toBe('/third2?deep[test]=123&deep[filter]=peter');
|
|
682
|
-
});
|
|
683
|
-
|
|
684
|
-
test('destructing params', async () => {
|
|
685
|
-
interface DTO {
|
|
686
|
-
name: string;
|
|
687
|
-
title: string;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
class Controller {
|
|
691
|
-
@http.GET('')
|
|
692
|
-
first({ name, title }: HttpBody<DTO>) {
|
|
693
|
-
return [name, title];
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
698
|
-
|
|
699
|
-
expect((await httpKernel.request(HttpRequest.GET('/').json({ name: 'Peter', title: 'CTO' }))).json).toEqual(['Peter', 'CTO']);
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
test('use http.response for serialization', async () => {
|
|
703
|
-
interface DefaultResponse {
|
|
704
|
-
title: string;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
interface ErrorResponse {
|
|
708
|
-
message: string;
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
class Controller {
|
|
712
|
-
@http.GET('/action1')
|
|
713
|
-
action1(): DefaultResponse[] {
|
|
714
|
-
return [{ title: 'a' }, { title: '1' }];
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
@http.GET('/action2').response<DefaultResponse[]>(200, `List`)
|
|
718
|
-
action2() {
|
|
719
|
-
return [{ title: 'a' }, { title: 1 }];
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
@http.GET('/action3')
|
|
723
|
-
.response<DefaultResponse[]>(200, `List`)
|
|
724
|
-
.response<ErrorResponse[]>(400, `Error`)
|
|
725
|
-
action3() {
|
|
726
|
-
return new JSONResponse([{ message: 'error' }, { message: 1 }]).status(400);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
731
|
-
expect((await httpKernel.request(HttpRequest.GET('/action1'))).json).toEqual([{ title: 'a' }, { title: '1' }]);
|
|
732
|
-
expect((await httpKernel.request(HttpRequest.GET('/action2'))).json).toEqual([{ title: 'a' }, { title: '1' }]);
|
|
733
|
-
expect((await httpKernel.request(HttpRequest.GET('/action3'))).json).toEqual([{ message: 'error' }, { message: '1' }]);
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
test('BodyValidation', async () => {
|
|
737
|
-
class User {
|
|
738
|
-
username!: string & MinLength<3>;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
class AddUserDto extends User {
|
|
742
|
-
imageUpload?: UploadedFile;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
class Controller {
|
|
746
|
-
@http.POST('/action1')
|
|
747
|
-
action1(user: HttpBody<User>): any {
|
|
748
|
-
return user;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
@http.POST('/action2')
|
|
752
|
-
action2(user: HttpBodyValidation<User>): User {
|
|
753
|
-
if (user.valid()) {
|
|
754
|
-
return user.value;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
throw new HttpBadRequestError('Invalid: ' + user.error.getErrorMessageForPath('username'));
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
@http.POST('/action3')
|
|
761
|
-
action3(user: HttpBodyValidation<AddUserDto>): User {
|
|
762
|
-
if (user.valid()) {
|
|
763
|
-
return user.value;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
throw new HttpBadRequestError('Invalid: ' + user.error.getErrorMessageForPath('username'));
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
const httpKernel = createHttpKernel([Controller]);
|
|
771
|
-
expect((await httpKernel.request(HttpRequest.POST('/action1').json({ username: 'Peter' }))).json).toEqual({ username: 'Peter' });
|
|
772
|
-
expect((await httpKernel.request(HttpRequest.POST('/action1').json({ username: 'Pe' }))).json).toEqual({
|
|
773
|
-
errors: [{ code: 'minLength', message: 'Min length is 3', path: 'username' }], message: 'Validation error:\nusername(minLength): Min length is 3'
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
expect((await httpKernel.request(HttpRequest.POST('/action2').json({ username: 'Peter' }))).json).toEqual({ username: 'Peter' });
|
|
777
|
-
expect((await httpKernel.request(HttpRequest.POST('/action2').json({ username: 'Pe' }))).bodyString).toEqual(`{"message":"Invalid: Min length is 3"}`);
|
|
778
|
-
|
|
779
|
-
expect((await httpKernel.request(HttpRequest.POST('/action3').json({ username: 'Peter' }))).json).toEqual({ username: 'Peter' });
|
|
780
|
-
expect((await httpKernel.request(HttpRequest.POST('/action3').json({ username: 'Pe' }))).bodyString).toEqual(`{"message":"Invalid: Min length is 3"}`);
|
|
781
|
-
});
|