@tsed/platform-params 8.0.1 → 8.0.3
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/lib/types/decorators/locals.d.ts +1 -1
- package/package.json +14 -13
- package/src/builder/PlatformParams.spec.ts +431 -0
- package/src/builder/PlatformParams.ts +86 -0
- package/src/decorators/bodyParams.spec.ts +121 -0
- package/src/decorators/bodyParams.ts +93 -0
- package/src/decorators/context.spec.ts +16 -0
- package/src/decorators/context.ts +70 -0
- package/src/decorators/cookies.spec.ts +19 -0
- package/src/decorators/cookies.ts +102 -0
- package/src/decorators/headerParams.spec.ts +16 -0
- package/src/decorators/headerParams.ts +49 -0
- package/src/decorators/locals.spec.ts +16 -0
- package/src/decorators/locals.ts +57 -0
- package/src/decorators/paramFn.ts +14 -0
- package/src/decorators/pathParams.spec.ts +58 -0
- package/src/decorators/pathParams.ts +97 -0
- package/src/decorators/queryParams.spec.ts +58 -0
- package/src/decorators/queryParams.ts +102 -0
- package/src/decorators/session.spec.ts +47 -0
- package/src/decorators/session.ts +51 -0
- package/src/decorators/useDeserialization.ts +14 -0
- package/src/decorators/useParam.spec.ts +82 -0
- package/src/decorators/useParam.ts +38 -0
- package/src/decorators/useParamExpression.ts +16 -0
- package/src/decorators/useParamType.ts +36 -0
- package/src/decorators/usePipe.ts +21 -0
- package/src/decorators/useType.ts +35 -0
- package/src/decorators/useValidation.ts +18 -0
- package/src/domain/ParamMetadata.ts +1 -0
- package/src/domain/ParamOptions.ts +12 -0
- package/src/domain/ParamTypes.ts +37 -0
- package/src/errors/ParamValidationError.spec.ts +152 -0
- package/src/errors/ParamValidationError.ts +38 -0
- package/src/errors/RequiredValidationError.spec.ts +49 -0
- package/src/errors/RequiredValidationError.ts +30 -0
- package/src/errors/ValidationError.spec.ts +18 -0
- package/src/errors/ValidationError.ts +11 -0
- package/src/exports.ts +1 -0
- package/src/index.ts +31 -0
- package/src/pipes/DeserializerPipe.spec.ts +39 -0
- package/src/pipes/DeserializerPipe.ts +15 -0
- package/src/pipes/ParseExpressionPipe.spec.ts +242 -0
- package/src/pipes/ParseExpressionPipe.ts +33 -0
- package/src/pipes/ValidationPipe.spec.ts +645 -0
- package/src/pipes/ValidationPipe.ts +112 -0
- package/src/utils/mapParamsOptions.spec.ts +28 -0
- package/src/utils/mapParamsOptions.ts +34 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ::: tip
|
|
5
5
|
* Locals are generally used by express and third-party like templating engine to render a page/template.
|
|
6
|
-
* See [Templating](
|
|
6
|
+
* See [Templating](https://tsed.dev/tutorials/templating.html) section for more details.
|
|
7
7
|
* :::
|
|
8
8
|
*
|
|
9
9
|
* #### Example
|
package/package.json
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
"name": "@tsed/platform-params",
|
|
3
3
|
"description": "Params module for Ts.ED Framework",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.0.
|
|
5
|
+
"version": "8.0.3",
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
7
|
"main": "./lib/esm/index.js",
|
|
8
8
|
"module": "./lib/esm/index.js",
|
|
9
9
|
"typings": "./lib/types/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
+
"@tsed/source": "./src/index.ts",
|
|
12
13
|
"types": "./lib/types/index.d.ts",
|
|
13
14
|
"import": "./lib/esm/index.js",
|
|
14
15
|
"default": "./lib/esm/index.js"
|
|
@@ -25,23 +26,23 @@
|
|
|
25
26
|
"tslib": "2.7.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@tsed/barrels": "8.0.
|
|
29
|
-
"@tsed/core": "8.0.
|
|
30
|
-
"@tsed/di": "8.0.
|
|
31
|
-
"@tsed/exceptions": "8.0.
|
|
32
|
-
"@tsed/json-mapper": "8.0.
|
|
33
|
-
"@tsed/schema": "8.0.
|
|
34
|
-
"@tsed/typescript": "8.0.
|
|
29
|
+
"@tsed/barrels": "8.0.3",
|
|
30
|
+
"@tsed/core": "8.0.3",
|
|
31
|
+
"@tsed/di": "8.0.3",
|
|
32
|
+
"@tsed/exceptions": "8.0.3",
|
|
33
|
+
"@tsed/json-mapper": "8.0.3",
|
|
34
|
+
"@tsed/schema": "8.0.3",
|
|
35
|
+
"@tsed/typescript": "8.0.3",
|
|
35
36
|
"eslint": "9.12.0",
|
|
36
37
|
"typescript": "5.4.5",
|
|
37
38
|
"vitest": "2.1.2"
|
|
38
39
|
},
|
|
39
40
|
"peerDependencies": {
|
|
40
|
-
"@tsed/core": "8.0.
|
|
41
|
-
"@tsed/di": "8.0.
|
|
42
|
-
"@tsed/exceptions": "8.0.
|
|
43
|
-
"@tsed/json-mapper": "8.0.
|
|
44
|
-
"@tsed/schema": "8.0.
|
|
41
|
+
"@tsed/core": "8.0.3",
|
|
42
|
+
"@tsed/di": "8.0.3",
|
|
43
|
+
"@tsed/exceptions": "8.0.3",
|
|
44
|
+
"@tsed/json-mapper": "8.0.3",
|
|
45
|
+
"@tsed/schema": "8.0.3"
|
|
45
46
|
},
|
|
46
47
|
"peerDependenciesMeta": {
|
|
47
48
|
"@tsed/core": {
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import {Injectable, ProviderScope} from "@tsed/di";
|
|
2
|
+
import {PlatformTest} from "@tsed/platform-http/testing";
|
|
3
|
+
|
|
4
|
+
import {buildPlatformParams, invokePlatformParams} from "../../test/helpers/buildPlatformParams.js";
|
|
5
|
+
import {PathParams} from "../decorators/pathParams.js";
|
|
6
|
+
import {QueryParams} from "../decorators/queryParams.js";
|
|
7
|
+
import {ParamTypes} from "../domain/ParamTypes.js";
|
|
8
|
+
|
|
9
|
+
describe("PlatformParams", () => {
|
|
10
|
+
beforeEach(() => PlatformTest.create());
|
|
11
|
+
afterEach(() => PlatformTest.reset());
|
|
12
|
+
describe("getArg()", () => {
|
|
13
|
+
it("should return REQUEST (node)", async () => {
|
|
14
|
+
// GIVEN
|
|
15
|
+
const {param, $ctx, h, platformParams} = await buildPlatformParams({
|
|
16
|
+
paramType: ParamTypes.NODE_REQUEST,
|
|
17
|
+
dataPath: "$ctx.request.req"
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// WHEN
|
|
21
|
+
const pipes = await platformParams.getPipes(param);
|
|
22
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
23
|
+
|
|
24
|
+
// THEN
|
|
25
|
+
expect(value).toEqual($ctx.getReq());
|
|
26
|
+
});
|
|
27
|
+
it("should return REQUEST (framework)", async () => {
|
|
28
|
+
// GIVEN
|
|
29
|
+
const {param, $ctx, h, platformParams} = await buildPlatformParams({
|
|
30
|
+
paramType: ParamTypes.REQUEST,
|
|
31
|
+
dataPath: "$ctx.request.request"
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// WHEN
|
|
35
|
+
const pipes = await platformParams.getPipes(param);
|
|
36
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
37
|
+
|
|
38
|
+
// THEN
|
|
39
|
+
expect(value).toEqual($ctx.getRequest());
|
|
40
|
+
});
|
|
41
|
+
it("should return REQUEST (platform)", async () => {
|
|
42
|
+
// GIVEN
|
|
43
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
44
|
+
paramType: ParamTypes.PLATFORM_REQUEST,
|
|
45
|
+
dataPath: "$ctx.request"
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// WHEN
|
|
49
|
+
const pipes = await platformParams.getPipes(param);
|
|
50
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
51
|
+
|
|
52
|
+
// THEN
|
|
53
|
+
expect(value).toEqual($ctx.request);
|
|
54
|
+
});
|
|
55
|
+
it("should return RESPONSE (node)", async () => {
|
|
56
|
+
// GIVEN
|
|
57
|
+
const {param, $ctx, h, platformParams} = await buildPlatformParams({
|
|
58
|
+
paramType: ParamTypes.NODE_RESPONSE,
|
|
59
|
+
dataPath: "$ctx.response.res"
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// WHEN
|
|
63
|
+
const pipes = await platformParams.getPipes(param);
|
|
64
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
65
|
+
|
|
66
|
+
// THEN
|
|
67
|
+
expect(value).toEqual($ctx.getRes());
|
|
68
|
+
});
|
|
69
|
+
it("should return RESPONSE (framework)", async () => {
|
|
70
|
+
// GIVEN
|
|
71
|
+
const {param, $ctx, h, platformParams} = await buildPlatformParams({
|
|
72
|
+
paramType: ParamTypes.RESPONSE,
|
|
73
|
+
dataPath: "$ctx.response.response"
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// WHEN
|
|
77
|
+
const pipes = await platformParams.getPipes(param);
|
|
78
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
79
|
+
|
|
80
|
+
// THEN
|
|
81
|
+
expect(value).toEqual($ctx.getResponse());
|
|
82
|
+
});
|
|
83
|
+
it("should return RESPONSE (platform)", async () => {
|
|
84
|
+
// GIVEN
|
|
85
|
+
const {param, $ctx, h, platformParams} = await buildPlatformParams({
|
|
86
|
+
paramType: ParamTypes.PLATFORM_RESPONSE,
|
|
87
|
+
dataPath: "$ctx.response"
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// WHEN
|
|
91
|
+
const pipes = await platformParams.getPipes(param);
|
|
92
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
93
|
+
|
|
94
|
+
// THEN
|
|
95
|
+
expect(value).toEqual($ctx.response);
|
|
96
|
+
});
|
|
97
|
+
it("should return NEXT", async () => {
|
|
98
|
+
// GIVEN
|
|
99
|
+
const {param, h, platformParams} = await buildPlatformParams({
|
|
100
|
+
paramType: ParamTypes.NEXT_FN,
|
|
101
|
+
dataPath: "next"
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// WHEN
|
|
105
|
+
const pipes = await platformParams.getPipes(param);
|
|
106
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
107
|
+
|
|
108
|
+
// THEN
|
|
109
|
+
expect(value).toBeInstanceOf(Function);
|
|
110
|
+
});
|
|
111
|
+
it("should return ERR", async () => {
|
|
112
|
+
// GIVEN
|
|
113
|
+
const {param, h, platformParams} = await buildPlatformParams({
|
|
114
|
+
paramType: ParamTypes.ERR,
|
|
115
|
+
dataPath: "$ctx.error"
|
|
116
|
+
});
|
|
117
|
+
h.$ctx.error = new Error();
|
|
118
|
+
|
|
119
|
+
// WHEN
|
|
120
|
+
const pipes = await platformParams.getPipes(param);
|
|
121
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
122
|
+
|
|
123
|
+
// THEN
|
|
124
|
+
expect(value).toEqual(h.$ctx.error);
|
|
125
|
+
});
|
|
126
|
+
it("should return $CTX", async () => {
|
|
127
|
+
// GIVEN
|
|
128
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
129
|
+
paramType: ParamTypes.$CTX,
|
|
130
|
+
dataPath: "$ctx"
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// WHEN
|
|
134
|
+
// @ts-ignore
|
|
135
|
+
const pipes = await platformParams.getPipes(param);
|
|
136
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
137
|
+
|
|
138
|
+
// THEN
|
|
139
|
+
expect(value).toEqual($ctx);
|
|
140
|
+
});
|
|
141
|
+
it("should return RESPONSE_DATA", async () => {
|
|
142
|
+
// GIVEN
|
|
143
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
144
|
+
paramType: ParamTypes.RESPONSE_DATA,
|
|
145
|
+
dataPath: "$ctx.data"
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// WHEN
|
|
149
|
+
const pipes = await platformParams.getPipes(param);
|
|
150
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
151
|
+
|
|
152
|
+
// THEN
|
|
153
|
+
expect(value).toEqual($ctx.data);
|
|
154
|
+
});
|
|
155
|
+
it("should return ENDPOINT_INFO", async () => {
|
|
156
|
+
// GIVEN
|
|
157
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
158
|
+
paramType: ParamTypes.ENDPOINT_INFO,
|
|
159
|
+
dataPath: "$ctx.endpoint"
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// @ts-ignore
|
|
163
|
+
$ctx.endpoint = "endpoint";
|
|
164
|
+
|
|
165
|
+
// WHEN
|
|
166
|
+
const pipes = await platformParams.getPipes(param);
|
|
167
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
168
|
+
|
|
169
|
+
// THEN
|
|
170
|
+
expect(value).toEqual($ctx.endpoint);
|
|
171
|
+
});
|
|
172
|
+
it("should return BODY", async () => {
|
|
173
|
+
// GIVEN
|
|
174
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
175
|
+
paramType: ParamTypes.BODY,
|
|
176
|
+
dataPath: "$ctx.request.body"
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// WHEN
|
|
180
|
+
const pipes = await platformParams.getPipes(param);
|
|
181
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
182
|
+
|
|
183
|
+
// THEN
|
|
184
|
+
expect(value).toEqual($ctx.getRequest().body);
|
|
185
|
+
});
|
|
186
|
+
it("should return PATH", async () => {
|
|
187
|
+
// GIVEN
|
|
188
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
189
|
+
paramType: ParamTypes.PATH,
|
|
190
|
+
dataPath: "$ctx.request.params"
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// WHEN
|
|
194
|
+
const pipes = await platformParams.getPipes(param);
|
|
195
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
196
|
+
|
|
197
|
+
// THEN
|
|
198
|
+
expect(value).toEqual($ctx.getRequest().params);
|
|
199
|
+
});
|
|
200
|
+
it("should return QUERY", async () => {
|
|
201
|
+
// GIVEN
|
|
202
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
203
|
+
paramType: ParamTypes.QUERY,
|
|
204
|
+
dataPath: "$ctx.request.query"
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// WHEN
|
|
208
|
+
const pipes = await platformParams.getPipes(param);
|
|
209
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
210
|
+
|
|
211
|
+
// THEN
|
|
212
|
+
expect(value).toEqual($ctx.getRequest().query);
|
|
213
|
+
});
|
|
214
|
+
it("should return HEADER", async () => {
|
|
215
|
+
// GIVEN
|
|
216
|
+
const {param, h, platformParams, ctx} = await buildPlatformParams({
|
|
217
|
+
paramType: ParamTypes.HEADER,
|
|
218
|
+
dataPath: "$ctx.request.headers"
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
ctx.request.raw.headers["accept"] = "application/json";
|
|
222
|
+
ctx.request.raw.headers["content-type"] = "application/json";
|
|
223
|
+
|
|
224
|
+
// WHEN
|
|
225
|
+
const pipes = await platformParams.getPipes(param);
|
|
226
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
227
|
+
|
|
228
|
+
// THEN
|
|
229
|
+
expect(value).toEqual({
|
|
230
|
+
accept: "application/json",
|
|
231
|
+
"content-type": "application/json"
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
it("should return COOKIES", async () => {
|
|
235
|
+
// GIVEN
|
|
236
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
237
|
+
paramType: ParamTypes.COOKIES,
|
|
238
|
+
dataPath: "$ctx.request.cookies"
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// WHEN
|
|
242
|
+
const pipes = await platformParams.getPipes(param);
|
|
243
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
244
|
+
|
|
245
|
+
// THEN
|
|
246
|
+
expect(value).toEqual($ctx.getRequest().cookies);
|
|
247
|
+
});
|
|
248
|
+
it("should return SESSION", async () => {
|
|
249
|
+
// GIVEN
|
|
250
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
251
|
+
paramType: ParamTypes.SESSION,
|
|
252
|
+
dataPath: "$ctx.request.session"
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// WHEN
|
|
256
|
+
const pipes = await platformParams.getPipes(param);
|
|
257
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
258
|
+
|
|
259
|
+
// THEN
|
|
260
|
+
expect(value).toEqual($ctx.request.session);
|
|
261
|
+
});
|
|
262
|
+
it("should return LOCALS", async () => {
|
|
263
|
+
// GIVEN
|
|
264
|
+
const {param, h, $ctx, platformParams} = await buildPlatformParams({
|
|
265
|
+
paramType: ParamTypes.LOCALS,
|
|
266
|
+
dataPath: "$ctx.response.locals"
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
h.$ctx.error = new Error();
|
|
270
|
+
|
|
271
|
+
// WHEN
|
|
272
|
+
const pipes = await platformParams.getPipes(param);
|
|
273
|
+
const value = await platformParams.getArg(h, pipes, param);
|
|
274
|
+
|
|
275
|
+
// THEN
|
|
276
|
+
expect(value).toEqual($ctx.getResponse().locals);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
describe("compileHandler()", () => {
|
|
280
|
+
it("should build all params and return value (SINGLETON)", async () => {
|
|
281
|
+
const platformParams = await invokePlatformParams();
|
|
282
|
+
|
|
283
|
+
@Injectable()
|
|
284
|
+
class MyCtrTest {
|
|
285
|
+
get(@PathParams() params: any, @QueryParams() query: any) {
|
|
286
|
+
return {params, query};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
PlatformTest.injector.addProvider(MyCtrTest);
|
|
291
|
+
|
|
292
|
+
const handler = await platformParams.compileHandler({
|
|
293
|
+
token: MyCtrTest,
|
|
294
|
+
propertyKey: "get"
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const $ctx = PlatformTest.createRequestContext({
|
|
298
|
+
event: {
|
|
299
|
+
request: {
|
|
300
|
+
query: {
|
|
301
|
+
test: "test"
|
|
302
|
+
},
|
|
303
|
+
params: {
|
|
304
|
+
s: "s"
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const result = await handler({
|
|
311
|
+
$ctx
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
expect(result).toEqual({
|
|
315
|
+
query: {
|
|
316
|
+
test: "test"
|
|
317
|
+
},
|
|
318
|
+
params: {
|
|
319
|
+
s: "s"
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
it("should build all params and return value (REQUEST)", async () => {
|
|
324
|
+
const platformParams = await invokePlatformParams();
|
|
325
|
+
|
|
326
|
+
@Injectable({
|
|
327
|
+
scope: ProviderScope.REQUEST
|
|
328
|
+
})
|
|
329
|
+
class MyCtrTest {
|
|
330
|
+
get(@PathParams() params: any, @QueryParams() query: any) {
|
|
331
|
+
return {params, query};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const $ctx = PlatformTest.createRequestContext({
|
|
336
|
+
event: {
|
|
337
|
+
request: {
|
|
338
|
+
query: {
|
|
339
|
+
test: "test"
|
|
340
|
+
},
|
|
341
|
+
params: {
|
|
342
|
+
s: "s"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
PlatformTest.injector.addProvider(MyCtrTest);
|
|
349
|
+
|
|
350
|
+
const handler = await platformParams.compileHandler({
|
|
351
|
+
token: MyCtrTest,
|
|
352
|
+
propertyKey: "get"
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const result = await handler({
|
|
356
|
+
$ctx
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
expect(result).toEqual({
|
|
360
|
+
query: {
|
|
361
|
+
test: "test"
|
|
362
|
+
},
|
|
363
|
+
params: {
|
|
364
|
+
s: "s"
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
it("should call without args", async () => {
|
|
369
|
+
const platformParams = await invokePlatformParams();
|
|
370
|
+
|
|
371
|
+
@Injectable()
|
|
372
|
+
class MyCtrTest {
|
|
373
|
+
get() {
|
|
374
|
+
return "test";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
PlatformTest.injector.addProvider(MyCtrTest);
|
|
379
|
+
|
|
380
|
+
const $ctx = PlatformTest.createRequestContext({
|
|
381
|
+
event: {
|
|
382
|
+
request: {
|
|
383
|
+
query: {
|
|
384
|
+
test: "test"
|
|
385
|
+
},
|
|
386
|
+
params: {
|
|
387
|
+
s: "s"
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const handler = await platformParams.compileHandler({
|
|
394
|
+
token: MyCtrTest,
|
|
395
|
+
propertyKey: "get"
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const result = await handler({
|
|
399
|
+
$ctx
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
expect(result).toEqual("test");
|
|
403
|
+
});
|
|
404
|
+
it("should return handler", async () => {
|
|
405
|
+
const platformParams = await invokePlatformParams();
|
|
406
|
+
|
|
407
|
+
const $ctx = PlatformTest.createRequestContext({
|
|
408
|
+
event: {
|
|
409
|
+
request: {
|
|
410
|
+
query: {
|
|
411
|
+
test: "test"
|
|
412
|
+
},
|
|
413
|
+
params: {
|
|
414
|
+
s: "s"
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const handler = await platformParams.compileHandler({
|
|
421
|
+
handler: ($ctx: any) => $ctx.request.query.test
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const result = await handler({
|
|
425
|
+
$ctx
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
expect(result).toEqual("test");
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {DIContext, Inject, Injectable, injectable, injector, InjectorService, ProviderScope, TokenProvider} from "@tsed/di";
|
|
2
|
+
import {JsonMethodStore, JsonParameterStore, PipeMethods} from "@tsed/schema";
|
|
3
|
+
|
|
4
|
+
import {ParamValidationError} from "../errors/ParamValidationError.js";
|
|
5
|
+
import {ParseExpressionPipe} from "../pipes/ParseExpressionPipe.js";
|
|
6
|
+
|
|
7
|
+
export type PlatformParamsScope<Context extends DIContext = DIContext> = {$ctx: Context} & Record<string, any>;
|
|
8
|
+
export type PlatformParamsCallback<Context extends DIContext = DIContext> = (scope: PlatformParamsScope<Context>) => Promise<any>;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Platform Params abstraction layer.
|
|
12
|
+
* @platform
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export class PlatformParams {
|
|
16
|
+
getPipes(param: JsonParameterStore) {
|
|
17
|
+
const get = (pipe: TokenProvider) => {
|
|
18
|
+
return injector().getProvider(pipe)!.priority || 0;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const sort = (p1: TokenProvider, p2: TokenProvider) => (get(p1) < get(p2) ? -1 : get(p1) > get(p2) ? 1 : 0);
|
|
22
|
+
const map = (token: TokenProvider) => injector().get<PipeMethods>(token)!;
|
|
23
|
+
|
|
24
|
+
return [ParseExpressionPipe, ...param.pipes.sort(sort)].map(map).filter(Boolean);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Return a handler with injectable parameters
|
|
29
|
+
* @param handlerMetadata
|
|
30
|
+
*/
|
|
31
|
+
compileHandler<Context extends DIContext = DIContext>({
|
|
32
|
+
propertyKey,
|
|
33
|
+
token,
|
|
34
|
+
handler
|
|
35
|
+
}: {
|
|
36
|
+
propertyKey?: string | symbol;
|
|
37
|
+
token?: any;
|
|
38
|
+
handler?: any;
|
|
39
|
+
}): PlatformParamsCallback<Context> {
|
|
40
|
+
if (!token || !propertyKey) {
|
|
41
|
+
return (scope: PlatformParamsScope<Context>) => handler(scope.$ctx);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const inj = injector();
|
|
45
|
+
const store = JsonMethodStore.fromMethod(token, propertyKey);
|
|
46
|
+
const getArguments = this.compile<Context>(store);
|
|
47
|
+
const provider = inj.getProvider(token)!;
|
|
48
|
+
|
|
49
|
+
return async (scope: PlatformParamsScope<Context>) => {
|
|
50
|
+
const container = provider.scope === ProviderScope.REQUEST ? scope.$ctx.container : undefined;
|
|
51
|
+
|
|
52
|
+
const [instance, args] = await Promise.all([inj.invoke<any>(token, {locals: container}), getArguments(scope)]);
|
|
53
|
+
|
|
54
|
+
return instance[propertyKey].call(instance, ...args, scope.$ctx);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
compile<Context extends DIContext = DIContext>(entity: JsonMethodStore): PlatformParamsCallback<Context> {
|
|
59
|
+
const params = JsonParameterStore.getParams(entity.target, entity.propertyKey);
|
|
60
|
+
const argsPipes = params.map((param) => {
|
|
61
|
+
return {
|
|
62
|
+
param,
|
|
63
|
+
pipes: this.getPipes(param)
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return (scope) => {
|
|
68
|
+
const promises = argsPipes.map(({param, pipes}) => this.getArg(scope, pipes, param));
|
|
69
|
+
return Promise.all(promises);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getArg<Context extends DIContext = DIContext>(scope: PlatformParamsScope, pipes: PipeMethods[], param: JsonParameterStore): Promise<any> {
|
|
74
|
+
return pipes.reduce(async (value: any | Promise<any>, pipe) => {
|
|
75
|
+
value = await value;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
return await pipe.transform(value, param);
|
|
79
|
+
} catch (er) {
|
|
80
|
+
throw ParamValidationError.from(param, er);
|
|
81
|
+
}
|
|
82
|
+
}, scope);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
injectable(PlatformParams).imports([ParseExpressionPipe]);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {Controller} from "@tsed/di";
|
|
2
|
+
import {getSpec, JsonParameterStore, Post, SpecTypes} from "@tsed/schema";
|
|
3
|
+
|
|
4
|
+
import {ParamTypes} from "../domain/ParamTypes.js";
|
|
5
|
+
import {BodyParams, RawBodyParams} from "./bodyParams.js";
|
|
6
|
+
|
|
7
|
+
describe("@BodyParams", () => {
|
|
8
|
+
it("should call useParam method with the correct parameters", () => {
|
|
9
|
+
class Test {}
|
|
10
|
+
|
|
11
|
+
class Ctrl {
|
|
12
|
+
test(@BodyParams("expression", Test) body: Test) {}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const param = JsonParameterStore.get(Ctrl, "test", 0);
|
|
16
|
+
expect(param.expression).toEqual("expression");
|
|
17
|
+
expect(param.paramType).toEqual(ParamTypes.BODY);
|
|
18
|
+
expect(param.type).toEqual(Test);
|
|
19
|
+
});
|
|
20
|
+
it("should create params with Buffer type", () => {
|
|
21
|
+
@Controller("/")
|
|
22
|
+
class MyCtrl {
|
|
23
|
+
@Post()
|
|
24
|
+
test(@BodyParams() body: Buffer) {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const spec = getSpec(MyCtrl, {specType: SpecTypes.OPENAPI});
|
|
28
|
+
|
|
29
|
+
expect(spec).toEqual({
|
|
30
|
+
paths: {
|
|
31
|
+
"/": {
|
|
32
|
+
post: {
|
|
33
|
+
operationId: "myCtrlTest",
|
|
34
|
+
parameters: [],
|
|
35
|
+
requestBody: {
|
|
36
|
+
content: {
|
|
37
|
+
"*/*": {
|
|
38
|
+
schema: {
|
|
39
|
+
type: "string"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
required: false
|
|
44
|
+
},
|
|
45
|
+
responses: {
|
|
46
|
+
"200": {
|
|
47
|
+
description: "Success"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
tags: ["MyCtrl"]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
tags: [
|
|
55
|
+
{
|
|
56
|
+
name: "MyCtrl"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("RawBodyParams()", () => {
|
|
64
|
+
it("should declare a RawBodyParams", () => {
|
|
65
|
+
@Controller("/")
|
|
66
|
+
class MyCtrl {
|
|
67
|
+
@Post()
|
|
68
|
+
test(@RawBodyParams() body: Buffer) {}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const spec = getSpec(MyCtrl, {specType: SpecTypes.OPENAPI});
|
|
72
|
+
|
|
73
|
+
expect(spec).toEqual({
|
|
74
|
+
paths: {
|
|
75
|
+
"/": {
|
|
76
|
+
post: {
|
|
77
|
+
operationId: "myCtrlTest",
|
|
78
|
+
parameters: [],
|
|
79
|
+
requestBody: {
|
|
80
|
+
content: {
|
|
81
|
+
"*/*": {
|
|
82
|
+
schema: {
|
|
83
|
+
type: "string"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
required: false
|
|
88
|
+
},
|
|
89
|
+
responses: {
|
|
90
|
+
"200": {
|
|
91
|
+
description: "Success"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
tags: ["MyCtrl"]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
tags: [
|
|
99
|
+
{
|
|
100
|
+
name: "MyCtrl"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const param = JsonParameterStore.get(MyCtrl, "test", 0);
|
|
106
|
+
expect(param.paramType).toEqual(ParamTypes.RAW_BODY);
|
|
107
|
+
expect(param.type).toEqual(Buffer);
|
|
108
|
+
expect(param.pipes).toHaveLength(0);
|
|
109
|
+
});
|
|
110
|
+
it("should declare RawBodyParams with options", () => {
|
|
111
|
+
class Ctrl {
|
|
112
|
+
test(@RawBodyParams({useValidation: true, useType: String}) param: Date) {}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const param = JsonParameterStore.get(Ctrl, "test", 0);
|
|
116
|
+
expect(param.expression).toEqual(undefined);
|
|
117
|
+
expect(param.paramType).toEqual(ParamTypes.RAW_BODY);
|
|
118
|
+
expect(param.type).toEqual(String);
|
|
119
|
+
expect(param.pipes).toHaveLength(1);
|
|
120
|
+
});
|
|
121
|
+
});
|