@loopback/rest 6.1.0 → 8.0.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/CHANGELOG.md +109 -0
- package/dist/body-parsers/body-parser.js +3 -0
- package/dist/body-parsers/body-parser.js.map +1 -1
- package/dist/coercion/coerce-parameter.d.ts +1 -1
- package/dist/coercion/coerce-parameter.js +36 -13
- package/dist/coercion/coerce-parameter.js.map +1 -1
- package/dist/coercion/utils.d.ts +1 -1
- package/dist/http-handler.js +5 -0
- package/dist/http-handler.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/providers/find-route.provider.d.ts +0 -2
- package/dist/providers/find-route.provider.js +11 -8
- package/dist/providers/find-route.provider.js.map +1 -1
- package/dist/providers/invoke-method.provider.d.ts +0 -2
- package/dist/providers/invoke-method.provider.js +21 -10
- package/dist/providers/invoke-method.provider.js.map +1 -1
- package/dist/providers/log-error.provider.js +7 -2
- package/dist/providers/log-error.provider.js.map +1 -1
- package/dist/providers/parse-params.provider.d.ts +0 -2
- package/dist/providers/parse-params.provider.js +16 -8
- package/dist/providers/parse-params.provider.js.map +1 -1
- package/dist/providers/reject.provider.d.ts +1 -1
- package/dist/providers/reject.provider.js +2 -1
- package/dist/providers/reject.provider.js.map +1 -1
- package/dist/providers/send.provider.d.ts +1 -4
- package/dist/providers/send.provider.js +11 -13
- package/dist/providers/send.provider.js.map +1 -1
- package/dist/request-context.js.map +1 -1
- package/dist/rest.application.js +1 -1
- package/dist/rest.application.js.map +1 -1
- package/dist/rest.server.d.ts +1 -0
- package/dist/rest.server.js +5 -4
- package/dist/rest.server.js.map +1 -1
- package/dist/router/base-route.js +3 -3
- package/dist/router/base-route.js.map +1 -1
- package/dist/router/controller-route.js +1 -1
- package/dist/router/controller-route.js.map +1 -1
- package/dist/router/handler-route.js +1 -1
- package/dist/router/handler-route.js.map +1 -1
- package/dist/router/redirect-route.js +1 -1
- package/dist/router/redirect-route.js.map +1 -1
- package/dist/sequence.js +1 -1
- package/dist/sequence.js.map +1 -1
- package/dist/spec-enhancers/consolidate.spec-enhancer.js +1 -1
- package/dist/spec-enhancers/consolidate.spec-enhancer.js.map +1 -1
- package/dist/spec-enhancers/info.spec-enhancer.js +13 -5
- package/dist/spec-enhancers/info.spec-enhancer.js.map +1 -1
- package/dist/validation/ajv-factory.provider.js +5 -3
- package/dist/validation/ajv-factory.provider.js.map +1 -1
- package/dist/validation/openapi-formats.d.ts +26 -0
- package/dist/validation/openapi-formats.js +85 -0
- package/dist/validation/openapi-formats.js.map +1 -0
- package/dist/validation/request-body.validator.d.ts +4 -4
- package/dist/validation/request-body.validator.js +5 -8
- package/dist/validation/request-body.validator.js.map +1 -1
- package/package.json +25 -22
- package/src/body-parsers/body-parser.ts +3 -0
- package/src/coercion/coerce-parameter.ts +43 -19
- package/src/http-handler.ts +6 -0
- package/src/providers/find-route.provider.ts +24 -8
- package/src/providers/invoke-method.provider.ts +28 -10
- package/src/providers/log-error.provider.ts +2 -1
- package/src/providers/parse-params.provider.ts +28 -8
- package/src/providers/reject.provider.ts +4 -3
- package/src/providers/send.provider.ts +9 -12
- package/src/request-context.ts +2 -1
- package/src/rest.application.ts +1 -1
- package/src/rest.server.ts +8 -5
- package/src/router/base-route.ts +3 -3
- package/src/router/controller-route.ts +1 -1
- package/src/router/handler-route.ts +3 -1
- package/src/router/redirect-route.ts +1 -1
- package/src/sequence.ts +2 -2
- package/src/spec-enhancers/consolidate.spec-enhancer.ts +2 -2
- package/src/spec-enhancers/info.spec-enhancer.ts +15 -6
- package/src/validation/ajv-factory.provider.ts +8 -4
- package/src/validation/openapi-formats.ts +92 -0
- package/src/validation/request-body.validator.ts +8 -8
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/rest
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.openapiFormats = exports.binaryFormat = exports.byteFormat = exports.doubleFormat = exports.floatFormat = exports.int64Format = exports.int32Format = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* int32: [-2147483648, 21474836 47]
|
|
10
|
+
*/
|
|
11
|
+
exports.int32Format = {
|
|
12
|
+
name: 'int32',
|
|
13
|
+
type: 'number',
|
|
14
|
+
validate: (value) => {
|
|
15
|
+
return (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647);
|
|
16
|
+
},
|
|
17
|
+
async: false,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* int64: [-9223372036854775808, 9223372036854775807]
|
|
21
|
+
*/
|
|
22
|
+
exports.int64Format = {
|
|
23
|
+
name: 'int64',
|
|
24
|
+
type: 'number',
|
|
25
|
+
validate: (value) => {
|
|
26
|
+
const max = Number.MAX_SAFE_INTEGER; // 9007199254740991
|
|
27
|
+
const min = Number.MIN_SAFE_INTEGER; // -9007199254740991
|
|
28
|
+
return Number.isInteger(value) && value >= min && value <= max;
|
|
29
|
+
},
|
|
30
|
+
async: false,
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* float: [-2^128, 2^128]
|
|
34
|
+
*/
|
|
35
|
+
exports.floatFormat = {
|
|
36
|
+
name: 'float',
|
|
37
|
+
type: 'number',
|
|
38
|
+
validate: (value) => {
|
|
39
|
+
return value >= -Math.pow(2, 128) && value <= Math.pow(2, 128);
|
|
40
|
+
},
|
|
41
|
+
async: false,
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* double: [-2^1024, 2^1024]
|
|
45
|
+
*/
|
|
46
|
+
exports.doubleFormat = {
|
|
47
|
+
name: 'double',
|
|
48
|
+
type: 'number',
|
|
49
|
+
validate: (value) => {
|
|
50
|
+
const max = Number.MAX_VALUE; // 1.7976931348623157e+308
|
|
51
|
+
const min = -Number.MAX_VALUE; // -1.7976931348623157e+308
|
|
52
|
+
return value >= min && value <= max;
|
|
53
|
+
},
|
|
54
|
+
async: false,
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Base64 encoded string
|
|
58
|
+
*/
|
|
59
|
+
exports.byteFormat = {
|
|
60
|
+
name: 'byte',
|
|
61
|
+
type: 'string',
|
|
62
|
+
validate: (value) => {
|
|
63
|
+
const base64 = Buffer.from(value, 'base64').toString('base64');
|
|
64
|
+
return value === base64;
|
|
65
|
+
},
|
|
66
|
+
async: false,
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Binary string
|
|
70
|
+
*/
|
|
71
|
+
exports.binaryFormat = {
|
|
72
|
+
name: 'binary',
|
|
73
|
+
type: 'string',
|
|
74
|
+
validate: (value) => true,
|
|
75
|
+
async: false,
|
|
76
|
+
};
|
|
77
|
+
exports.openapiFormats = [
|
|
78
|
+
exports.int32Format,
|
|
79
|
+
exports.int64Format,
|
|
80
|
+
exports.floatFormat,
|
|
81
|
+
exports.doubleFormat,
|
|
82
|
+
exports.byteFormat,
|
|
83
|
+
exports.binaryFormat,
|
|
84
|
+
];
|
|
85
|
+
//# sourceMappingURL=openapi-formats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-formats.js","sourceRoot":"","sources":["../../src/validation/openapi-formats.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;;AAIhE;;GAEG;AACU,QAAA,WAAW,GAAc;IACpC,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;QAC1B,OAAO,CACL,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,UAAU,IAAI,KAAK,IAAI,UAAU,CACvE,CAAC;IACJ,CAAC;IACD,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;GAEG;AACU,QAAA,WAAW,GAAc;IACpC,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;QAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC,mBAAmB;QACxD,MAAM,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB;QACzD,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC;IACjE,CAAC;IACD,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;GAEG;AACU,QAAA,WAAW,GAAc;IACpC,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;QAC1B,OAAO,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC;IACD,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;GAEG;AACU,QAAA,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;QAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,0BAA0B;QACxD,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,2BAA2B;QAC1D,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC;IACtC,CAAC;IACD,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;GAEG;AACU,QAAA,UAAU,GAAc;IACnC,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC/D,OAAO,KAAK,KAAK,MAAM,CAAC;IAC1B,CAAC;IACD,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;GAEG;AACU,QAAA,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI;IACjC,KAAK,EAAE,KAAK;CACb,CAAC;AAEW,QAAA,cAAc,GAAgB;IACzC,mBAAW;IACX,mBAAW;IACX,mBAAW;IACX,oBAAY;IACZ,kBAAU;IACV,oBAAY;CACb,CAAC"}
|
|
@@ -13,10 +13,10 @@ import { ValidationOptions, ValueValidationOptions } from '../types';
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function validateRequestBody(body: RequestBody, requestBodySpec?: RequestBodyObject, globalSchemas?: SchemasObject, options?: ValidationOptions): Promise<void>;
|
|
15
15
|
/**
|
|
16
|
-
* Validate the
|
|
17
|
-
* @param
|
|
16
|
+
* Validate the value against JSON schema.
|
|
17
|
+
* @param value - The data value.
|
|
18
18
|
* @param schema - The JSON schema used to perform the validation.
|
|
19
19
|
* @param globalSchemas - Schema references.
|
|
20
|
-
* @param options -
|
|
20
|
+
* @param options - Value validation options.
|
|
21
21
|
*/
|
|
22
|
-
export declare function validateValueAgainstSchema(value: any, schema: SchemaObject | ReferenceObject, globalSchemas?: SchemasObject, options?: ValueValidationOptions): Promise<
|
|
22
|
+
export declare function validateValueAgainstSchema(value: any, schema: SchemaObject | ReferenceObject, globalSchemas?: SchemasObject, options?: ValueValidationOptions): Promise<any>;
|
|
@@ -85,11 +85,11 @@ function getKeyForOptions(options = ajv_factory_provider_1.DEFAULT_AJV_VALIDATIO
|
|
|
85
85
|
return JSON.stringify(ajvOptions);
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
|
-
* Validate the
|
|
89
|
-
* @param
|
|
88
|
+
* Validate the value against JSON schema.
|
|
89
|
+
* @param value - The data value.
|
|
90
90
|
* @param schema - The JSON schema used to perform the validation.
|
|
91
91
|
* @param globalSchemas - Schema references.
|
|
92
|
-
* @param options -
|
|
92
|
+
* @param options - Value validation options.
|
|
93
93
|
*/
|
|
94
94
|
async function validateValueAgainstSchema(
|
|
95
95
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -114,11 +114,8 @@ value, schema, globalSchemas = {}, options = {}) {
|
|
|
114
114
|
let validationErrors = [];
|
|
115
115
|
try {
|
|
116
116
|
const validationResult = await validate(value);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
debug(`Value from ${options.source} passed AJV validation.`);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
117
|
+
debug(`Value from ${options.source} passed AJV validation.`, validationResult);
|
|
118
|
+
return validationResult;
|
|
122
119
|
}
|
|
123
120
|
catch (error) {
|
|
124
121
|
validationErrors = error.errors;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-body.validator.js","sourceRoot":"","sources":["../../src/validation/request-body.validator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"request-body.validator.js","sourceRoot":"","sources":["../../src/validation/request-body.validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopback/rest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Expose controllers as REST endpoints and route REST API requests to controller methods",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": "
|
|
8
|
+
"node": "^10.16 || 12 || 14"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"acceptance": "lb-mocha \"dist/__tests__/acceptance/**/*.js\"",
|
|
@@ -23,53 +23,56 @@
|
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@loopback/core": "^2.11.0"
|
|
28
|
+
},
|
|
26
29
|
"dependencies": {
|
|
27
|
-
"@loopback/
|
|
28
|
-
"@loopback/
|
|
29
|
-
"@loopback/
|
|
30
|
-
"@loopback/openapi-v3": "^3.4.8",
|
|
30
|
+
"@loopback/express": "^2.1.0",
|
|
31
|
+
"@loopback/http-server": "^2.3.0",
|
|
32
|
+
"@loopback/openapi-v3": "^5.0.0",
|
|
31
33
|
"@openapi-contrib/openapi-schema-to-json-schema": "^3.0.4",
|
|
32
34
|
"@types/body-parser": "^1.19.0",
|
|
33
35
|
"@types/cors": "^2.8.7",
|
|
34
|
-
"@types/express": "^4.17.
|
|
35
|
-
"@types/express-serve-static-core": "^4.17.
|
|
36
|
+
"@types/express": "^4.17.8",
|
|
37
|
+
"@types/express-serve-static-core": "^4.17.13",
|
|
36
38
|
"@types/http-errors": "^1.8.0",
|
|
37
39
|
"@types/on-finished": "^2.3.1",
|
|
38
40
|
"@types/serve-static": "1.13.5",
|
|
39
41
|
"@types/type-is": "^1.6.3",
|
|
40
|
-
"ajv": "^6.12.
|
|
42
|
+
"ajv": "^6.12.5",
|
|
41
43
|
"ajv-errors": "^1.0.1",
|
|
42
44
|
"ajv-keywords": "^3.5.2",
|
|
43
45
|
"body-parser": "^1.19.0",
|
|
44
46
|
"cors": "^2.8.5",
|
|
45
|
-
"debug": "^4.
|
|
47
|
+
"debug": "^4.2.0",
|
|
46
48
|
"express": "^4.17.1",
|
|
47
49
|
"http-errors": "^1.8.0",
|
|
48
50
|
"js-yaml": "^3.14.0",
|
|
49
51
|
"json-schema-compare": "^0.2.2",
|
|
50
52
|
"lodash": "^4.17.20",
|
|
51
53
|
"on-finished": "^2.3.0",
|
|
52
|
-
"path-to-regexp": "^6.
|
|
54
|
+
"path-to-regexp": "^6.2.0",
|
|
53
55
|
"qs": "^6.9.4",
|
|
54
56
|
"strong-error-handler": "^3.5.0",
|
|
55
|
-
"tslib": "^2.0.
|
|
57
|
+
"tslib": "^2.0.2",
|
|
56
58
|
"type-is": "^1.6.18",
|
|
57
|
-
"validator": "^13.1.
|
|
59
|
+
"validator": "^13.1.17"
|
|
58
60
|
},
|
|
59
61
|
"devDependencies": {
|
|
60
|
-
"@loopback/build": "^6.2.
|
|
61
|
-
"@loopback/
|
|
62
|
-
"@loopback/
|
|
63
|
-
"@loopback/
|
|
64
|
-
"@loopback/
|
|
62
|
+
"@loopback/build": "^6.2.5",
|
|
63
|
+
"@loopback/core": "^2.11.0",
|
|
64
|
+
"@loopback/eslint-config": "^10.0.1",
|
|
65
|
+
"@loopback/openapi-spec-builder": "^3.0.0",
|
|
66
|
+
"@loopback/repository": "^3.1.0",
|
|
67
|
+
"@loopback/testlab": "^3.2.7",
|
|
65
68
|
"@types/debug": "^4.1.5",
|
|
66
69
|
"@types/js-yaml": "^3.12.5",
|
|
67
70
|
"@types/json-schema-compare": "^0.2.0",
|
|
68
|
-
"@types/lodash": "^4.14.
|
|
71
|
+
"@types/lodash": "^4.14.161",
|
|
69
72
|
"@types/multer": "^1.4.4",
|
|
70
|
-
"@types/node": "^10.17.
|
|
73
|
+
"@types/node": "^10.17.35",
|
|
71
74
|
"@types/on-finished": "^2.3.1",
|
|
72
|
-
"@types/qs": "^6.9.
|
|
75
|
+
"@types/qs": "^6.9.5",
|
|
73
76
|
"multer": "^1.4.2"
|
|
74
77
|
},
|
|
75
78
|
"files": [
|
|
@@ -83,5 +86,5 @@
|
|
|
83
86
|
"url": "https://github.com/strongloop/loopback-next.git",
|
|
84
87
|
"directory": "packages/rest"
|
|
85
88
|
},
|
|
86
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "390f2794d10eea3d969ae417963af815ce1bc417"
|
|
87
90
|
}
|
|
@@ -61,15 +61,18 @@ export class RequestBodyParser {
|
|
|
61
61
|
if (customParser) {
|
|
62
62
|
// Invoke the custom parser
|
|
63
63
|
const body = await this._invokeCustomParser(customParser, request);
|
|
64
|
+
debug('Parsed request body', body);
|
|
64
65
|
return Object.assign(requestBody, body);
|
|
65
66
|
} else {
|
|
66
67
|
const parser = this._findParser(matchedMediaType);
|
|
67
68
|
if (parser) {
|
|
68
69
|
const body = await parser.parse(request);
|
|
70
|
+
debug('Parsed request body', body);
|
|
69
71
|
return Object.assign(requestBody, body);
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
} catch (err) {
|
|
75
|
+
debug('Request body parsing error', err);
|
|
73
76
|
throw normalizeParsingError(err);
|
|
74
77
|
}
|
|
75
78
|
|
|
@@ -13,10 +13,10 @@ import debugModule from 'debug';
|
|
|
13
13
|
import {
|
|
14
14
|
RestHttpErrors,
|
|
15
15
|
validateValueAgainstSchema,
|
|
16
|
-
ValidationOptions,
|
|
17
16
|
ValueValidationOptions,
|
|
18
17
|
} from '../';
|
|
19
18
|
import {parseJson} from '../parse-json';
|
|
19
|
+
import {ValidationOptions} from '../types';
|
|
20
20
|
import {DEFAULT_AJV_VALIDATION_OPTIONS} from '../validation/ajv-factory.provider';
|
|
21
21
|
import {
|
|
22
22
|
DateCoercionOptions,
|
|
@@ -61,31 +61,51 @@ export async function coerceParameter(
|
|
|
61
61
|
validator.validateParamBeforeCoercion(data);
|
|
62
62
|
if (data === undefined) return data;
|
|
63
63
|
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
let result: any = data;
|
|
66
|
+
|
|
64
67
|
switch (OAIType) {
|
|
65
68
|
case 'byte':
|
|
66
|
-
|
|
69
|
+
result = coerceBuffer(data, spec);
|
|
70
|
+
break;
|
|
67
71
|
case 'date':
|
|
68
|
-
|
|
72
|
+
result = coerceDatetime(data, spec, {dateOnly: true});
|
|
73
|
+
break;
|
|
69
74
|
case 'date-time':
|
|
70
|
-
|
|
75
|
+
result = coerceDatetime(data, spec);
|
|
76
|
+
break;
|
|
71
77
|
case 'float':
|
|
72
78
|
case 'double':
|
|
73
79
|
case 'number':
|
|
74
|
-
|
|
80
|
+
result = coerceNumber(data, spec);
|
|
81
|
+
break;
|
|
75
82
|
case 'long':
|
|
76
|
-
|
|
83
|
+
result = coerceInteger(data, spec, {isLong: true});
|
|
84
|
+
break;
|
|
77
85
|
case 'integer':
|
|
78
|
-
|
|
86
|
+
result = coerceInteger(data, spec);
|
|
87
|
+
break;
|
|
79
88
|
case 'boolean':
|
|
80
|
-
|
|
89
|
+
result = coerceBoolean(data, spec);
|
|
90
|
+
break;
|
|
81
91
|
case 'object':
|
|
82
|
-
|
|
92
|
+
result = await coerceObject(data, spec);
|
|
93
|
+
break;
|
|
83
94
|
case 'string':
|
|
84
95
|
case 'password':
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
result = coerceString(data, spec);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (result != null) {
|
|
101
|
+
// For date/date-time/byte, we need to pass the raw string value to AJV
|
|
102
|
+
if (OAIType === 'date' || OAIType === 'date-time' || OAIType === 'byte') {
|
|
103
|
+
await validateParam(spec, data, options);
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
result = await validateParam(spec, result, options);
|
|
88
107
|
}
|
|
108
|
+
return result;
|
|
89
109
|
}
|
|
90
110
|
|
|
91
111
|
function coerceString(data: string | object, spec: ParameterObject) {
|
|
@@ -165,11 +185,7 @@ function coerceBoolean(data: string | object, spec: ParameterObject) {
|
|
|
165
185
|
throw RestHttpErrors.invalidData(data, spec.name);
|
|
166
186
|
}
|
|
167
187
|
|
|
168
|
-
async function coerceObject(
|
|
169
|
-
input: string | object,
|
|
170
|
-
spec: ParameterObject,
|
|
171
|
-
options: ValidationOptions = DEFAULT_AJV_VALIDATION_OPTIONS,
|
|
172
|
-
) {
|
|
188
|
+
async function coerceObject(input: string | object, spec: ParameterObject) {
|
|
173
189
|
const data = parseJsonIfNeeded(input, spec);
|
|
174
190
|
|
|
175
191
|
if (data == null) {
|
|
@@ -180,17 +196,25 @@ async function coerceObject(
|
|
|
180
196
|
if (typeof data !== 'object' || Array.isArray(data))
|
|
181
197
|
throw RestHttpErrors.invalidData(input, spec.name);
|
|
182
198
|
|
|
199
|
+
return data;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function validateParam(
|
|
203
|
+
spec: ParameterObject,
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
205
|
+
data: any,
|
|
206
|
+
options: ValidationOptions = DEFAULT_AJV_VALIDATION_OPTIONS,
|
|
207
|
+
) {
|
|
183
208
|
const schema = extractSchemaFromSpec(spec);
|
|
184
209
|
if (schema) {
|
|
185
210
|
// Apply coercion based on properties defined by spec.schema
|
|
186
|
-
|
|
211
|
+
return validateValueAgainstSchema(
|
|
187
212
|
data,
|
|
188
213
|
schema,
|
|
189
214
|
{},
|
|
190
215
|
{...options, coerceTypes: true, source: 'parameter', name: spec.name},
|
|
191
216
|
);
|
|
192
217
|
}
|
|
193
|
-
|
|
194
218
|
return data;
|
|
195
219
|
}
|
|
196
220
|
|
package/src/http-handler.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
import {Context} from '@loopback/core';
|
|
7
|
+
import {MIDDLEWARE_CONTEXT} from '@loopback/express';
|
|
7
8
|
import {
|
|
8
9
|
ComponentsObject,
|
|
9
10
|
ControllerSpec,
|
|
@@ -109,6 +110,11 @@ export class HttpHandler {
|
|
|
109
110
|
this._serverConfig,
|
|
110
111
|
);
|
|
111
112
|
|
|
113
|
+
// Set the request context as a property of Express request object so that
|
|
114
|
+
// downstream Express native integration can access `RequestContext`
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
116
|
+
(request as any)[MIDDLEWARE_CONTEXT] = requestContext;
|
|
117
|
+
|
|
112
118
|
const sequence = await requestContext.get<SequenceHandler>(
|
|
113
119
|
RestBindings.SEQUENCE,
|
|
114
120
|
);
|
|
@@ -3,14 +3,23 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
BindingScope,
|
|
8
|
+
Context,
|
|
9
|
+
inject,
|
|
10
|
+
injectable,
|
|
11
|
+
Provider,
|
|
12
|
+
} from '@loopback/core';
|
|
7
13
|
import {asMiddleware, Middleware} from '@loopback/express';
|
|
14
|
+
import debugFactory from 'debug';
|
|
8
15
|
import {HttpHandler} from '../http-handler';
|
|
9
16
|
import {RestBindings, RestTags} from '../keys';
|
|
10
17
|
import {ResolvedRoute} from '../router';
|
|
11
18
|
import {RestMiddlewareGroups} from '../sequence';
|
|
12
19
|
import {FindRoute, Request} from '../types';
|
|
13
20
|
|
|
21
|
+
const debug = debugFactory('loopback:rest:find-route');
|
|
22
|
+
|
|
14
23
|
export class FindRouteProvider implements Provider<FindRoute> {
|
|
15
24
|
constructor(
|
|
16
25
|
@inject(RestBindings.Http.CONTEXT) protected context: Context,
|
|
@@ -23,26 +32,33 @@ export class FindRouteProvider implements Provider<FindRoute> {
|
|
|
23
32
|
|
|
24
33
|
action(request: Request): ResolvedRoute {
|
|
25
34
|
const found = this.handler.findRoute(request);
|
|
35
|
+
debug('Route found for %s %s', request.method, request.originalUrl, found);
|
|
26
36
|
found.updateBindings(this.context);
|
|
27
37
|
return found;
|
|
28
38
|
}
|
|
29
39
|
}
|
|
30
40
|
|
|
31
|
-
@
|
|
41
|
+
@injectable(
|
|
32
42
|
asMiddleware({
|
|
33
43
|
group: RestMiddlewareGroups.FIND_ROUTE,
|
|
34
44
|
chain: RestTags.REST_MIDDLEWARE_CHAIN,
|
|
35
45
|
}),
|
|
46
|
+
{scope: BindingScope.SINGLETON},
|
|
36
47
|
)
|
|
37
48
|
export class FindRouteMiddlewareProvider implements Provider<Middleware> {
|
|
38
|
-
constructor(
|
|
39
|
-
@inject(RestBindings.SequenceActions.FIND_ROUTE)
|
|
40
|
-
protected findRoute: FindRoute,
|
|
41
|
-
) {}
|
|
42
|
-
|
|
43
49
|
value(): Middleware {
|
|
44
50
|
return async (ctx, next) => {
|
|
45
|
-
const
|
|
51
|
+
const request = ctx.request;
|
|
52
|
+
debug('Finding route for %s %s', request.method, request.originalUrl);
|
|
53
|
+
const handler = await ctx.get(RestBindings.HANDLER);
|
|
54
|
+
const route = handler.findRoute(request);
|
|
55
|
+
debug(
|
|
56
|
+
'Route found for %s %s',
|
|
57
|
+
request.method,
|
|
58
|
+
request.originalUrl,
|
|
59
|
+
route,
|
|
60
|
+
);
|
|
61
|
+
route.updateBindings(ctx);
|
|
46
62
|
ctx.bind(RestBindings.Operation.ROUTE).to(route);
|
|
47
63
|
return next();
|
|
48
64
|
};
|
|
@@ -3,13 +3,22 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
BindingScope,
|
|
8
|
+
Context,
|
|
9
|
+
inject,
|
|
10
|
+
injectable,
|
|
11
|
+
Provider,
|
|
12
|
+
} from '@loopback/core';
|
|
7
13
|
import {asMiddleware, Middleware} from '@loopback/express';
|
|
14
|
+
import debugFactory from 'debug';
|
|
8
15
|
import {RestBindings, RestTags} from '../keys';
|
|
9
16
|
import {RouteEntry} from '../router';
|
|
10
17
|
import {RestMiddlewareGroups} from '../sequence';
|
|
11
18
|
import {InvokeMethod, OperationArgs, OperationRetval} from '../types';
|
|
12
19
|
|
|
20
|
+
const debug = debugFactory('loopback:rest:invoke-method');
|
|
21
|
+
|
|
13
22
|
export class InvokeMethodProvider implements Provider<InvokeMethod> {
|
|
14
23
|
constructor(@inject(RestBindings.Http.CONTEXT) protected context: Context) {}
|
|
15
24
|
|
|
@@ -22,28 +31,37 @@ export class InvokeMethodProvider implements Provider<InvokeMethod> {
|
|
|
22
31
|
}
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
@
|
|
34
|
+
@injectable(
|
|
26
35
|
asMiddleware({
|
|
27
36
|
group: RestMiddlewareGroups.INVOKE_METHOD,
|
|
28
37
|
upstreamGroups: RestMiddlewareGroups.PARSE_PARAMS,
|
|
29
38
|
chain: RestTags.REST_MIDDLEWARE_CHAIN,
|
|
30
39
|
}),
|
|
40
|
+
{scope: BindingScope.SINGLETON},
|
|
31
41
|
)
|
|
32
42
|
export class InvokeMethodMiddlewareProvider implements Provider<Middleware> {
|
|
33
|
-
constructor(
|
|
34
|
-
@inject(RestBindings.SequenceActions.INVOKE_METHOD)
|
|
35
|
-
protected invokeMethod: InvokeMethod,
|
|
36
|
-
) {}
|
|
37
|
-
|
|
38
43
|
value(): Middleware {
|
|
39
44
|
return async (ctx, next) => {
|
|
40
45
|
const route: RouteEntry = await ctx.get(RestBindings.Operation.ROUTE);
|
|
41
46
|
const params: OperationArgs = await ctx.get(
|
|
42
47
|
RestBindings.Operation.PARAMS,
|
|
43
48
|
);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
if (debug.enabled) {
|
|
50
|
+
debug('Invoking method %s with', route.describe(), params);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const retVal = await route.invokeHandler(ctx, params);
|
|
54
|
+
ctx.bind(RestBindings.Operation.RETURN_VALUE).to(retVal);
|
|
55
|
+
if (debug.enabled) {
|
|
56
|
+
debug('Return value from %s', route.describe(), retVal);
|
|
57
|
+
}
|
|
58
|
+
return retVal;
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (debug.enabled) {
|
|
61
|
+
debug('Error thrown from %s', route.describe(), err);
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
47
65
|
};
|
|
48
66
|
}
|
|
49
67
|
}
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {Provider} from '@loopback/core';
|
|
6
|
+
import {BindingScope, injectable, Provider} from '@loopback/core';
|
|
7
7
|
import {LogError, Request} from '../types';
|
|
8
8
|
|
|
9
|
+
@injectable({scope: BindingScope.SINGLETON})
|
|
9
10
|
export class LogErrorProvider implements Provider<LogError> {
|
|
10
11
|
value(): LogError {
|
|
11
12
|
return (err, statusCode, req) => this.action(err, statusCode, req);
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {BindingScope, inject, injectable, Provider} from '@loopback/core';
|
|
7
7
|
import {asMiddleware, Middleware} from '@loopback/express';
|
|
8
|
+
import debugFactory from 'debug';
|
|
8
9
|
import {RequestBodyParser} from '../body-parsers';
|
|
9
10
|
import {RestBindings, RestTags} from '../keys';
|
|
10
11
|
import {parseOperationArgs} from '../parser';
|
|
@@ -12,6 +13,9 @@ import {ResolvedRoute} from '../router';
|
|
|
12
13
|
import {RestMiddlewareGroups} from '../sequence';
|
|
13
14
|
import {AjvFactory, ParseParams, Request, ValidationOptions} from '../types';
|
|
14
15
|
import {DEFAULT_AJV_VALIDATION_OPTIONS} from '../validation/ajv-factory.provider';
|
|
16
|
+
|
|
17
|
+
const debug = debugFactory('loopback:rest:parse-param');
|
|
18
|
+
|
|
15
19
|
/**
|
|
16
20
|
* Provides the function for parsing args in requests at runtime.
|
|
17
21
|
*
|
|
@@ -39,24 +43,40 @@ export class ParseParamsProvider implements Provider<ParseParams> {
|
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
@
|
|
46
|
+
@injectable(
|
|
43
47
|
asMiddleware({
|
|
44
48
|
group: RestMiddlewareGroups.PARSE_PARAMS,
|
|
45
49
|
upstreamGroups: RestMiddlewareGroups.FIND_ROUTE,
|
|
46
50
|
chain: RestTags.REST_MIDDLEWARE_CHAIN,
|
|
47
51
|
}),
|
|
52
|
+
{scope: BindingScope.SINGLETON},
|
|
48
53
|
)
|
|
49
54
|
export class ParseParamsMiddlewareProvider implements Provider<Middleware> {
|
|
50
|
-
constructor(
|
|
51
|
-
@inject(RestBindings.SequenceActions.PARSE_PARAMS)
|
|
52
|
-
protected parseParams: ParseParams,
|
|
53
|
-
) {}
|
|
54
|
-
|
|
55
55
|
value(): Middleware {
|
|
56
56
|
return async (ctx, next) => {
|
|
57
|
+
const requestBodyParser = await ctx.get(RestBindings.REQUEST_BODY_PARSER);
|
|
58
|
+
const validationOptions: ValidationOptions =
|
|
59
|
+
(await ctx.get(
|
|
60
|
+
RestBindings.REQUEST_BODY_PARSER_OPTIONS.deepProperty('validation'),
|
|
61
|
+
{optional: true},
|
|
62
|
+
)) ?? DEFAULT_AJV_VALIDATION_OPTIONS;
|
|
63
|
+
const ajvFactory = await ctx.get(RestBindings.AJV_FACTORY, {
|
|
64
|
+
optional: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
57
67
|
const route: ResolvedRoute = await ctx.get(RestBindings.Operation.ROUTE);
|
|
58
|
-
|
|
68
|
+
debug('Parsing parameters for %s %s', route.verb, route.path);
|
|
69
|
+
const params = await parseOperationArgs(
|
|
70
|
+
ctx.request,
|
|
71
|
+
route,
|
|
72
|
+
requestBodyParser,
|
|
73
|
+
{
|
|
74
|
+
ajvFactory: ajvFactory,
|
|
75
|
+
...validationOptions,
|
|
76
|
+
},
|
|
77
|
+
);
|
|
59
78
|
ctx.bind(RestBindings.Operation.PARAMS).to(params);
|
|
79
|
+
debug('Parameters', params);
|
|
60
80
|
return next();
|
|
61
81
|
};
|
|
62
82
|
}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {inject, Provider} from '@loopback/core';
|
|
6
|
+
import {BindingScope, inject, injectable, Provider} from '@loopback/core';
|
|
8
7
|
import {HttpError} from 'http-errors';
|
|
8
|
+
import {ErrorWriterOptions, writeErrorToResponse} from 'strong-error-handler';
|
|
9
9
|
import {RestBindings} from '../keys';
|
|
10
|
-
import {
|
|
10
|
+
import {HandlerContext, LogError, Reject} from '../types';
|
|
11
11
|
|
|
12
12
|
// TODO(bajtos) Make this mapping configurable at RestServer level,
|
|
13
13
|
// allow apps and extensions to contribute additional mappings.
|
|
@@ -15,6 +15,7 @@ const codeToStatusCodeMap: {[key: string]: number} = {
|
|
|
15
15
|
ENTITY_NOT_FOUND: 404,
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
@injectable({scope: BindingScope.SINGLETON})
|
|
18
19
|
export class RejectProvider implements Provider<Reject> {
|
|
19
20
|
constructor(
|
|
20
21
|
@inject(RestBindings.SequenceActions.LOG_ERROR)
|