@loopback/rest 1.23.0 → 1.26.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 +41 -0
- package/dist/body-parsers/body-parser.helpers.js +5 -2
- package/dist/body-parsers/body-parser.helpers.js.map +1 -1
- package/dist/body-parsers/body-parser.js +8 -4
- package/dist/body-parsers/body-parser.js.map +1 -1
- package/dist/coercion/coerce-parameter.js +9 -4
- package/dist/coercion/coerce-parameter.js.map +1 -1
- package/dist/coercion/utils.js +5 -2
- package/dist/coercion/utils.js.map +1 -1
- package/dist/coercion/validator.js +4 -2
- package/dist/coercion/validator.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +13 -10
- package/dist/index.js.map +1 -1
- package/dist/keys.d.ts +1 -1
- package/dist/parser.js +7 -3
- package/dist/parser.js.map +1 -1
- package/dist/providers/log-error.provider.js +2 -1
- package/dist/providers/log-error.provider.js.map +1 -1
- package/dist/request-context.js +17 -11
- package/dist/request-context.js.map +1 -1
- package/dist/rest-http-error.d.ts +1 -1
- package/dist/rest-http-error.js +11 -8
- package/dist/rest-http-error.js.map +1 -1
- package/dist/rest.component.js +2 -1
- package/dist/rest.component.js.map +1 -1
- package/dist/rest.server.d.ts +2 -2
- package/dist/rest.server.js +20 -15
- package/dist/rest.server.js.map +1 -1
- package/dist/router/base-route.d.ts +8 -1
- package/dist/router/base-route.js +13 -0
- package/dist/router/base-route.js.map +1 -1
- package/dist/router/controller-route.js +10 -6
- package/dist/router/controller-route.js.map +1 -1
- package/dist/router/external-express-routes.d.ts +1 -1
- package/dist/router/external-express-routes.js +11 -8
- package/dist/router/external-express-routes.js.map +1 -1
- package/dist/router/handler-route.js +1 -1
- package/dist/router/handler-route.js.map +1 -1
- package/dist/router/openapi-path.js +18 -21
- package/dist/router/openapi-path.js.map +1 -1
- package/dist/router/router-base.js +2 -1
- package/dist/router/router-base.js.map +1 -1
- package/dist/router/routing-table.js +12 -8
- package/dist/router/routing-table.js.map +1 -1
- package/dist/router/trie-router.js +2 -1
- package/dist/router/trie-router.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/validation/request-body.validator.js +19 -14
- package/dist/validation/request-body.validator.js.map +1 -1
- package/dist/writer.js +2 -1
- package/dist/writer.js.map +1 -1
- package/package.json +19 -19
- package/src/body-parsers/body-parser.helpers.ts +1 -1
- package/src/body-parsers/body-parser.ts +3 -3
- package/src/coercion/coerce-parameter.ts +3 -3
- package/src/coercion/utils.ts +1 -1
- package/src/coercion/validator.ts +2 -2
- package/src/index.ts +11 -14
- package/src/keys.ts +1 -1
- package/src/parser.ts +2 -2
- package/src/providers/log-error.provider.ts +1 -1
- package/src/request-context.ts +10 -10
- package/src/rest-http-error.ts +4 -5
- package/src/rest.component.ts +1 -1
- package/src/rest.server.ts +11 -11
- package/src/router/base-route.ts +13 -1
- package/src/router/controller-route.ts +7 -5
- package/src/router/external-express-routes.ts +3 -4
- package/src/router/handler-route.ts +8 -2
- package/src/router/openapi-path.ts +24 -29
- package/src/router/router-base.ts +1 -1
- package/src/router/routing-table.ts +5 -5
- package/src/router/trie-router.ts +1 -1
- package/src/types.ts +1 -1
- package/src/validation/request-body.validator.ts +7 -7
- package/src/writer.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing-table.js","sourceRoot":"","sources":["../../src/router/routing-table.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE
|
|
1
|
+
{"version":3,"file":"routing-table.js","sourceRoot":"","sources":["../../src/router/routing-table.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,6 +37,7 @@ let TrieRouter = class TrieRouter extends router_base_1.BaseRouter {
|
|
|
37
37
|
this.trie.create(key, route);
|
|
38
38
|
}
|
|
39
39
|
findRouteWithPathVars(verb, path) {
|
|
40
|
+
var _a;
|
|
40
41
|
const key = this.getKey(verb, path);
|
|
41
42
|
const found = this.trie.match(key);
|
|
42
43
|
debug('Route matched: %j', found);
|
|
@@ -44,7 +45,7 @@ let TrieRouter = class TrieRouter extends router_base_1.BaseRouter {
|
|
|
44
45
|
const route = found.node.value;
|
|
45
46
|
if (route) {
|
|
46
47
|
debug('Route found: %s', util_1.inspect(route, { depth: 5 }));
|
|
47
|
-
return route_entry_1.createResolvedRoute(route, found.params
|
|
48
|
+
return route_entry_1.createResolvedRoute(route, (_a = found.params, (_a !== null && _a !== void 0 ? _a : {})));
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trie-router.js","sourceRoot":"","sources":["../../src/router/trie-router.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;;;;;;;;;;;;;AAEhE,+CAAyC;AACzC,+BAA6B;AAC7B,kCAAqC;AAErC,+CAA8D;AAC9D,+CAAyC;AACzC,iCAA4B;AAE5B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,2BAA2B,CAAC,CAAC;AAE5D;;GAEG;AACH,IAAa,UAAU,GAAvB,MAAa,UAAW,SAAQ,wBAAU;IAGxC,YAEE,OAA2B;QAE3B,KAAK,CAAC,OAAO,CAAC,CAAC;QANT,SAAI,GAAG,IAAI,WAAI,EAAc,CAAC;IAOtC,CAAC;IAES,oBAAoB,CAAC,KAAiB;QAC9C,4BAA4B;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAES,qBAAqB,CAAC,IAAY,EAAE,IAAY
|
|
1
|
+
{"version":3,"file":"trie-router.js","sourceRoot":"","sources":["../../src/router/trie-router.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;;;;;;;;;;;;;AAEhE,+CAAyC;AACzC,+BAA6B;AAC7B,kCAAqC;AAErC,+CAA8D;AAC9D,+CAAyC;AACzC,iCAA4B;AAE5B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,2BAA2B,CAAC,CAAC;AAE5D;;GAEG;AACH,IAAa,UAAU,GAAvB,MAAa,UAAW,SAAQ,wBAAU;IAGxC,YAEE,OAA2B;QAE3B,KAAK,CAAC,OAAO,CAAC,CAAC;QANT,SAAI,GAAG,IAAI,WAAI,EAAc,CAAC;IAOtC,CAAC;IAES,oBAAoB,CAAC,KAAiB;QAC9C,4BAA4B;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAES,qBAAqB,CAAC,IAAY,EAAE,IAAY;;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;QAElC,IAAI,KAAK,EAAE;YACT,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAM,CAAC;YAChC,IAAI,KAAK,EAAE;gBACT,KAAK,CAAC,iBAAiB,EAAE,cAAO,CAAC,KAAK,EAAE,EAAC,KAAK,EAAE,CAAC,EAAC,CAAC,CAAC,CAAC;gBACrD,OAAO,iCAAmB,CAAC,KAAK,QAAE,KAAK,CAAC,MAAM,uCAAI,EAAE,GAAC,CAAC;aACvD;SACF;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAES,sBAAsB;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;CACF,CAAA;AAnCY,UAAU;IAIlB,WAAA,gBAAM,CAAC,mBAAY,CAAC,cAAc,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAA;;GAJ7C,UAAU,CAmCtB;AAnCY,gCAAU"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Binding, BoundValue } from '@loopback/context';
|
|
2
2
|
import { ReferenceObject, SchemaObject } from '@loopback/openapi-v3';
|
|
3
|
-
import
|
|
3
|
+
import ajv from 'ajv';
|
|
4
4
|
import { Options, OptionsJson, OptionsText, OptionsUrlencoded } from 'body-parser';
|
|
5
5
|
import { Request, Response } from 'express';
|
|
6
6
|
import { ResolvedRoute, RouteEntry } from './router';
|
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
// Node module: @loopback/rest
|
|
4
4
|
// This file is licensed under the MIT License.
|
|
5
5
|
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
6
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
10
|
const openapi_v3_1 = require("@loopback/openapi-v3");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
11
|
+
const ajv_1 = __importDefault(require("ajv"));
|
|
12
|
+
const debug_1 = __importDefault(require("debug"));
|
|
13
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
14
|
+
const util_1 = __importDefault(require("util"));
|
|
12
15
|
const __1 = require("..");
|
|
13
16
|
const toJsonSchema = require('openapi-schema-to-json-schema');
|
|
14
|
-
const debug =
|
|
17
|
+
const debug = debug_1.default('loopback:rest:validation');
|
|
15
18
|
const ajvKeywords = require('ajv-keywords');
|
|
16
19
|
/**
|
|
17
20
|
* Check whether the request body is valid according to the provided OpenAPI schema.
|
|
@@ -24,7 +27,8 @@ const ajvKeywords = require('ajv-keywords');
|
|
|
24
27
|
* @param options - Request body validation options for AJV
|
|
25
28
|
*/
|
|
26
29
|
function validateRequestBody(body, requestBodySpec, globalSchemas = {}, options = {}) {
|
|
27
|
-
|
|
30
|
+
var _a;
|
|
31
|
+
const required = (_a = requestBodySpec) === null || _a === void 0 ? void 0 : _a.required;
|
|
28
32
|
if (required && body.value == null) {
|
|
29
33
|
const err = Object.assign(new __1.HttpErrors.BadRequest('Request body is required'), {
|
|
30
34
|
code: 'MISSING_REQUIRED_PARAMETER',
|
|
@@ -35,12 +39,12 @@ function validateRequestBody(body, requestBodySpec, globalSchemas = {}, options
|
|
|
35
39
|
const schema = body.schema;
|
|
36
40
|
/* istanbul ignore if */
|
|
37
41
|
if (debug.enabled) {
|
|
38
|
-
debug('Request body schema:',
|
|
42
|
+
debug('Request body schema:', util_1.default.inspect(schema, { depth: null }));
|
|
39
43
|
if (schema &&
|
|
40
44
|
openapi_v3_1.isReferenceObject(schema) &&
|
|
41
45
|
schema.$ref.startsWith('#/components/schemas/')) {
|
|
42
46
|
const ref = schema.$ref.slice('#/components/schemas/'.length);
|
|
43
|
-
debug(' referencing:',
|
|
47
|
+
debug(' referencing:', util_1.default.inspect(globalSchemas[ref], { depth: null }));
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
if (!schema)
|
|
@@ -58,7 +62,7 @@ function convertToJsonSchema(openapiSchema) {
|
|
|
58
62
|
delete jsonSchema['$schema'];
|
|
59
63
|
/* istanbul ignore if */
|
|
60
64
|
if (debug.enabled) {
|
|
61
|
-
debug('Converted OpenAPI schema to JSON schema: %s',
|
|
65
|
+
debug('Converted OpenAPI schema to JSON schema: %s', util_1.default.inspect(jsonSchema, { depth: null }));
|
|
62
66
|
}
|
|
63
67
|
return jsonSchema;
|
|
64
68
|
}
|
|
@@ -91,8 +95,9 @@ function getKeyForOptions(options) {
|
|
|
91
95
|
function validateValueAgainstSchema(
|
|
92
96
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
97
|
body, schema, globalSchemas = {}, options = {}) {
|
|
98
|
+
var _a;
|
|
94
99
|
let validate;
|
|
95
|
-
const cache = options.compiledSchemaCache
|
|
100
|
+
const cache = (_a = options.compiledSchemaCache, (_a !== null && _a !== void 0 ? _a : DEFAULT_COMPILED_SCHEMA_CACHE));
|
|
96
101
|
const key = getKeyForOptions(options);
|
|
97
102
|
let validatorMap;
|
|
98
103
|
if (cache.has(schema)) {
|
|
@@ -101,7 +106,7 @@ body, schema, globalSchemas = {}, options = {}) {
|
|
|
101
106
|
}
|
|
102
107
|
if (!validate) {
|
|
103
108
|
validate = createValidator(schema, globalSchemas, options);
|
|
104
|
-
validatorMap = validatorMap
|
|
109
|
+
validatorMap = (validatorMap !== null && validatorMap !== void 0 ? validatorMap : new Map());
|
|
105
110
|
validatorMap.set(key, validate);
|
|
106
111
|
cache.set(schema, validatorMap);
|
|
107
112
|
}
|
|
@@ -112,13 +117,13 @@ body, schema, globalSchemas = {}, options = {}) {
|
|
|
112
117
|
let validationErrors = validate.errors;
|
|
113
118
|
/* istanbul ignore if */
|
|
114
119
|
if (debug.enabled) {
|
|
115
|
-
debug('Invalid request body: %s. Errors: %s',
|
|
120
|
+
debug('Invalid request body: %s. Errors: %s', util_1.default.inspect(body, { depth: null }), util_1.default.inspect(validationErrors));
|
|
116
121
|
}
|
|
117
122
|
if (typeof options.ajvErrorTransformer === 'function') {
|
|
118
123
|
validationErrors = options.ajvErrorTransformer(validationErrors);
|
|
119
124
|
}
|
|
120
125
|
const error = __1.RestHttpErrors.invalidRequestBody();
|
|
121
|
-
error.details =
|
|
126
|
+
error.details = lodash_1.default.map(validationErrors, e => {
|
|
122
127
|
return {
|
|
123
128
|
path: e.dataPath,
|
|
124
129
|
code: e.keyword,
|
|
@@ -141,7 +146,7 @@ function createValidator(schema, globalSchemas, options) {
|
|
|
141
146
|
nullable: true,
|
|
142
147
|
}, options);
|
|
143
148
|
debug('AJV options', options);
|
|
144
|
-
const ajv = new
|
|
149
|
+
const ajv = new ajv_1.default(options);
|
|
145
150
|
if (options.ajvKeywords === true) {
|
|
146
151
|
ajvKeywords(ajv);
|
|
147
152
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-body.validator.js","sourceRoot":"","sources":["../../src/validation/request-body.validator.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE
|
|
1
|
+
{"version":3,"file":"request-body.validator.js","sourceRoot":"","sources":["../../src/validation/request-body.validator.ts"],"names":[],"mappings":"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"}
|
package/dist/writer.js
CHANGED
|
@@ -17,6 +17,7 @@ function writeResultToResponse(
|
|
|
17
17
|
response,
|
|
18
18
|
// result returned back from invoking controller method
|
|
19
19
|
result) {
|
|
20
|
+
var _a;
|
|
20
21
|
// Bypass response writing if the controller method returns `response` itself
|
|
21
22
|
// or the response headers have been sent
|
|
22
23
|
if (result === response || response.headersSent) {
|
|
@@ -27,7 +28,7 @@ result) {
|
|
|
27
28
|
response.end();
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
30
|
-
const isStream = result instanceof stream_1.Readable || typeof (result
|
|
31
|
+
const isStream = result instanceof stream_1.Readable || typeof ((_a = result) === null || _a === void 0 ? void 0 : _a.pipe) === 'function';
|
|
31
32
|
if (isStream) {
|
|
32
33
|
response.setHeader('Content-Type', 'application/octet-stream');
|
|
33
34
|
// Stream
|
package/dist/writer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;AAGhE,mCAAgC;AAEhC;;;;;;GAMG;AACH,SAAgB,qBAAqB;AACnC,+DAA+D;AAC/D,QAAkB;AAClB,uDAAuD;AACvD,MAAuB
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;AAGhE,mCAAgC;AAEhC;;;;;;GAMG;AACH,SAAgB,qBAAqB;AACnC,+DAA+D;AAC/D,QAAkB;AAClB,uDAAuD;AACvD,MAAuB;;IAEvB,6EAA6E;IAC7E,yCAAyC;IACzC,IAAI,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,WAAW,EAAE;QAC/C,OAAO;KACR;IACD,IAAI,MAAM,KAAK,SAAS,EAAE;QACxB,QAAQ,CAAC,UAAU,GAAG,GAAG,CAAC;QAC1B,QAAQ,CAAC,GAAG,EAAE,CAAC;QACf,OAAO;KACR;IAED,MAAM,QAAQ,GACZ,MAAM,YAAY,iBAAQ,IAAI,cAAO,MAAM,0CAAE,IAAI,CAAA,KAAK,UAAU,CAAC;IAEnE,IAAI,QAAQ,EAAE;QACZ,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;QAC/D,SAAS;QACT,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,OAAO;KACR;IACD,QAAQ,OAAO,MAAM,EAAE;QACrB,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC;QACf,KAAK,QAAQ;YACX,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;gBAC3B,yBAAyB;gBACzB,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;aAChE;iBAAM;gBACL,kDAAkD;gBAClD,6DAA6D;gBAC7D,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;gBACvD,wDAAwD;gBACxD,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;aACjC;YACD,MAAM;QACR;YACE,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YACjD,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM;KACT;IACD,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvB,CAAC;AA/CD,sDA+CC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopback/rest",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=8.9"
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
"copyright.owner": "IBM Corp.",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@loopback/context": "^
|
|
23
|
-
"@loopback/core": "^1.
|
|
24
|
-
"@loopback/http-server": "^1.
|
|
25
|
-
"@loopback/openapi-v3": "^1.
|
|
22
|
+
"@loopback/context": "^2.0.0",
|
|
23
|
+
"@loopback/core": "^1.12.2",
|
|
24
|
+
"@loopback/http-server": "^1.5.2",
|
|
25
|
+
"@loopback/openapi-v3": "^1.12.0",
|
|
26
26
|
"@types/body-parser": "^1.17.1",
|
|
27
27
|
"@types/cors": "^2.8.6",
|
|
28
28
|
"@types/express": "^4.17.2",
|
|
29
|
-
"@types/express-serve-static-core": "^4.
|
|
30
|
-
"@types/http-errors": "^1.6.
|
|
29
|
+
"@types/express-serve-static-core": "^4.17.2",
|
|
30
|
+
"@types/http-errors": "^1.6.3",
|
|
31
31
|
"@types/on-finished": "^2.3.1",
|
|
32
32
|
"@types/serve-static": "1.13.3",
|
|
33
33
|
"@types/type-is": "^1.6.3",
|
|
34
|
-
"ajv": "^6.
|
|
34
|
+
"ajv": "^6.11.0",
|
|
35
35
|
"ajv-keywords": "^3.4.1",
|
|
36
36
|
"body-parser": "^1.19.0",
|
|
37
37
|
"cors": "^2.8.5",
|
|
@@ -42,23 +42,23 @@
|
|
|
42
42
|
"lodash": "^4.17.15",
|
|
43
43
|
"on-finished": "^2.3.0",
|
|
44
44
|
"openapi-schema-to-json-schema": "^2.2.0",
|
|
45
|
-
"path-to-regexp": "^
|
|
45
|
+
"path-to-regexp": "^6.1.0",
|
|
46
46
|
"qs": "^6.9.1",
|
|
47
47
|
"strong-error-handler": "^3.4.0",
|
|
48
48
|
"type-is": "^1.6.18",
|
|
49
|
-
"validator": "^12.
|
|
49
|
+
"validator": "^12.2.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@loopback/build": "^
|
|
53
|
-
"@loopback/eslint-config": "^
|
|
54
|
-
"@loopback/openapi-spec-builder": "^1.
|
|
55
|
-
"@loopback/repository": "^1.
|
|
56
|
-
"@loopback/testlab": "^1.
|
|
52
|
+
"@loopback/build": "^3.1.0",
|
|
53
|
+
"@loopback/eslint-config": "^5.0.2",
|
|
54
|
+
"@loopback/openapi-spec-builder": "^1.3.0",
|
|
55
|
+
"@loopback/repository": "^1.18.0",
|
|
56
|
+
"@loopback/testlab": "^1.10.2",
|
|
57
57
|
"@types/debug": "^4.1.5",
|
|
58
|
-
"@types/js-yaml": "^3.12.
|
|
59
|
-
"@types/lodash": "^4.14.
|
|
58
|
+
"@types/js-yaml": "^3.12.2",
|
|
59
|
+
"@types/lodash": "^4.14.149",
|
|
60
60
|
"@types/multer": "^1.3.10",
|
|
61
|
-
"@types/node": "^10.17.
|
|
61
|
+
"@types/node": "^10.17.13",
|
|
62
62
|
"@types/on-finished": "^2.3.1",
|
|
63
63
|
"@types/qs": "^6.9.0",
|
|
64
64
|
"multer": "^1.4.2"
|
|
@@ -76,5 +76,5 @@
|
|
|
76
76
|
"url": "https://github.com/strongloop/loopback-next.git",
|
|
77
77
|
"directory": "packages/rest"
|
|
78
78
|
},
|
|
79
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "d08f135a0d1040edc61497739a8d86a866e4e29a"
|
|
80
80
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
OptionsText,
|
|
10
10
|
OptionsUrlencoded,
|
|
11
11
|
} from 'body-parser';
|
|
12
|
-
import
|
|
12
|
+
import debugModule from 'debug';
|
|
13
13
|
import {HttpError} from 'http-errors';
|
|
14
14
|
import {Request, RequestBodyParserOptions, Response} from '../types';
|
|
15
15
|
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
instantiateClass,
|
|
13
13
|
} from '@loopback/context';
|
|
14
14
|
import {isReferenceObject, OperationObject} from '@loopback/openapi-v3';
|
|
15
|
-
import
|
|
15
|
+
import debugModule from 'debug';
|
|
16
16
|
import {is} from 'type-is';
|
|
17
17
|
import {RestHttpErrors} from '../rest-http-error';
|
|
18
18
|
import {Request} from '../types';
|
|
@@ -38,7 +38,7 @@ export class RequestBodyParser {
|
|
|
38
38
|
parsers?: BodyParser[],
|
|
39
39
|
@inject.context() private readonly ctx?: Context,
|
|
40
40
|
) {
|
|
41
|
-
this.parsers = sortParsers(parsers
|
|
41
|
+
this.parsers = sortParsers(parsers ?? []);
|
|
42
42
|
if (debug.enabled) {
|
|
43
43
|
debug(
|
|
44
44
|
'Body parsers: ',
|
|
@@ -88,7 +88,7 @@ export class RequestBodyParser {
|
|
|
88
88
|
};
|
|
89
89
|
if (!operationSpec.requestBody) return {requestBody};
|
|
90
90
|
|
|
91
|
-
const contentType = getContentType(request)
|
|
91
|
+
const contentType = getContentType(request) ?? 'application/json';
|
|
92
92
|
debug('Loading request body with content type %j', contentType);
|
|
93
93
|
|
|
94
94
|
// the type of `operationSpec.requestBody` could be `RequestBodyObject`
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
import {isReferenceObject, ParameterObject} from '@loopback/openapi-v3';
|
|
7
|
-
import
|
|
7
|
+
import debugModule from 'debug';
|
|
8
8
|
import {RestHttpErrors} from '../';
|
|
9
9
|
import {parseJson} from '../parse-json';
|
|
10
10
|
import {
|
|
@@ -96,7 +96,7 @@ function coerceDatetime(
|
|
|
96
96
|
if (typeof data === 'object' || isEmpty(data))
|
|
97
97
|
throw RestHttpErrors.invalidData(data, spec.name);
|
|
98
98
|
|
|
99
|
-
if (options
|
|
99
|
+
if (options?.dateOnly) {
|
|
100
100
|
if (!matchDateFormat(data))
|
|
101
101
|
throw RestHttpErrors.invalidData(data, spec.name);
|
|
102
102
|
} else {
|
|
@@ -131,7 +131,7 @@ function coerceInteger(
|
|
|
131
131
|
const coercedInt = Number(data);
|
|
132
132
|
if (isNaN(coercedInt!)) throw RestHttpErrors.invalidData(data, spec.name);
|
|
133
133
|
|
|
134
|
-
if (options
|
|
134
|
+
if (options?.isLong) {
|
|
135
135
|
if (!Number.isInteger(coercedInt))
|
|
136
136
|
throw RestHttpErrors.invalidData(data, spec.name);
|
|
137
137
|
} else {
|
package/src/coercion/utils.ts
CHANGED
|
@@ -52,7 +52,7 @@ export class Validator {
|
|
|
52
52
|
*/
|
|
53
53
|
isRequired(opts?: ValidationOptions) {
|
|
54
54
|
if (this.ctx.parameterSpec.required) return true;
|
|
55
|
-
if (opts
|
|
55
|
+
if (opts?.required) return true;
|
|
56
56
|
return false;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -65,7 +65,7 @@ export class Validator {
|
|
|
65
65
|
isAbsent(value: any) {
|
|
66
66
|
if (value === '' || value === undefined) return true;
|
|
67
67
|
|
|
68
|
-
const schema: SchemaObject = this.ctx.parameterSpec.schema
|
|
68
|
+
const schema: SchemaObject = this.ctx.parameterSpec.schema ?? {};
|
|
69
69
|
if (schema.type === 'object' && value === 'null') return true;
|
|
70
70
|
|
|
71
71
|
return false;
|
package/src/index.ts
CHANGED
|
@@ -3,27 +3,24 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
export * from '
|
|
7
|
-
|
|
8
|
-
export * from './providers';
|
|
9
|
-
|
|
10
|
-
export * from './parser';
|
|
6
|
+
export * from '@loopback/openapi-v3';
|
|
11
7
|
export * from './body-parsers';
|
|
12
|
-
export * from './writer';
|
|
13
8
|
export * from './http-handler';
|
|
14
|
-
export * from './request-context';
|
|
15
|
-
export * from './types';
|
|
16
9
|
export * from './keys';
|
|
10
|
+
export * from './parse-json';
|
|
11
|
+
export * from './parser';
|
|
12
|
+
export * from './providers';
|
|
13
|
+
export * from './request-context';
|
|
14
|
+
export * from './rest-http-error';
|
|
17
15
|
export * from './rest.application';
|
|
18
16
|
export * from './rest.component';
|
|
19
17
|
export * from './rest.server';
|
|
18
|
+
export * from './router';
|
|
20
19
|
export * from './sequence';
|
|
21
|
-
export * from './
|
|
22
|
-
export * from './parse-json';
|
|
20
|
+
export * from './types';
|
|
23
21
|
export * from './validation/request-body.validator';
|
|
24
|
-
|
|
25
|
-
// export all errors from external http-errors package
|
|
26
|
-
import * as HttpErrors from 'http-errors';
|
|
22
|
+
export * from './writer';
|
|
27
23
|
export {HttpErrors};
|
|
28
24
|
|
|
29
|
-
export
|
|
25
|
+
// export all errors from external http-errors package
|
|
26
|
+
import HttpErrors from 'http-errors';
|
package/src/keys.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {BindingKey, Context} from '@loopback/context';
|
|
|
7
7
|
import {CoreBindings} from '@loopback/core';
|
|
8
8
|
import {HttpProtocol} from '@loopback/http-server';
|
|
9
9
|
import {OpenApiSpec, OperationObject} from '@loopback/openapi-v3';
|
|
10
|
-
import
|
|
10
|
+
import https from 'https';
|
|
11
11
|
import {ErrorWriterOptions} from 'strong-error-handler';
|
|
12
12
|
import {BodyParser, RequestBodyParser} from './body-parsers';
|
|
13
13
|
import {HttpHandler} from './http-handler';
|
package/src/parser.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
REQUEST_BODY_INDEX,
|
|
11
11
|
SchemasObject,
|
|
12
12
|
} from '@loopback/openapi-v3';
|
|
13
|
-
import
|
|
13
|
+
import debugFactory from 'debug';
|
|
14
14
|
import {RequestBody, RequestBodyParser} from './body-parsers';
|
|
15
15
|
import {coerceParameter} from './coercion/coerce-parameter';
|
|
16
16
|
import {RestHttpErrors} from './rest-http-error';
|
|
@@ -75,7 +75,7 @@ function buildOperationArguments(
|
|
|
75
75
|
|
|
76
76
|
const paramArgs: OperationArgs = [];
|
|
77
77
|
|
|
78
|
-
for (const paramSpec of operationSpec.parameters
|
|
78
|
+
for (const paramSpec of operationSpec.parameters ?? []) {
|
|
79
79
|
if (isReferenceObject(paramSpec)) {
|
|
80
80
|
// TODO(bajtos) implement $ref parameters
|
|
81
81
|
// See https://github.com/strongloop/loopback-next/issues/435
|
package/src/request-context.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
import {Context} from '@loopback/context';
|
|
7
|
-
import
|
|
7
|
+
import onFinished from 'on-finished';
|
|
8
8
|
import {RestBindings} from './keys';
|
|
9
9
|
import {RestServerResolvedConfig} from './rest.server';
|
|
10
10
|
import {HandlerContext, Request, Response} from './types';
|
|
@@ -22,9 +22,9 @@ export class RequestContext extends Context implements HandlerContext {
|
|
|
22
22
|
*/
|
|
23
23
|
get requestedProtocol(): string {
|
|
24
24
|
return (
|
|
25
|
-
(this.request.get('x-forwarded-proto')
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
((this.request.get('x-forwarded-proto') ?? '').split(',')[0] ||
|
|
26
|
+
this.request.protocol ||
|
|
27
|
+
this.serverConfig.protocol) ??
|
|
28
28
|
'http'
|
|
29
29
|
);
|
|
30
30
|
}
|
|
@@ -36,7 +36,7 @@ export class RequestContext extends Context implements HandlerContext {
|
|
|
36
36
|
*/
|
|
37
37
|
get basePath(): string {
|
|
38
38
|
const request = this.request;
|
|
39
|
-
let basePath = this.serverConfig.basePath
|
|
39
|
+
let basePath = this.serverConfig.basePath ?? '';
|
|
40
40
|
if (request.baseUrl && request.baseUrl !== '/') {
|
|
41
41
|
if (!basePath || request.baseUrl.endsWith(basePath)) {
|
|
42
42
|
// Express has already applied basePath to baseUrl
|
|
@@ -67,16 +67,16 @@ export class RequestContext extends Context implements HandlerContext {
|
|
|
67
67
|
// 127.0.0.1:3000
|
|
68
68
|
// 127.0.0.1
|
|
69
69
|
let {host, port} = parseHostAndPort(
|
|
70
|
-
request.get('x-forwarded-host')
|
|
70
|
+
request.get('x-forwarded-host') ?? request.headers.host,
|
|
71
71
|
);
|
|
72
72
|
|
|
73
|
-
const forwardedPort = (request.get('x-forwarded-port')
|
|
73
|
+
const forwardedPort = (request.get('x-forwarded-port') ?? '').split(',')[0];
|
|
74
74
|
port = forwardedPort || port;
|
|
75
75
|
|
|
76
76
|
if (!host) {
|
|
77
77
|
// No host detected from http headers
|
|
78
78
|
// Use the configured values or the local network address
|
|
79
|
-
host = config.host
|
|
79
|
+
host = config.host ?? request.socket.localAddress;
|
|
80
80
|
port = (config.port || request.socket.localPort).toString();
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -122,10 +122,10 @@ export class RequestContext extends Context implements HandlerContext {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
function parseHostAndPort(host: string | undefined) {
|
|
125
|
-
host = host
|
|
125
|
+
host = host ?? '';
|
|
126
126
|
host = host.split(',')[0];
|
|
127
127
|
const portPattern = /:([0-9]+)$/;
|
|
128
|
-
const port = (host.match(portPattern)
|
|
128
|
+
const port = (host.match(portPattern) ?? [])[1] || '';
|
|
129
129
|
host = host.replace(portPattern, '');
|
|
130
130
|
return {host, port};
|
|
131
131
|
}
|
package/src/rest-http-error.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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 HttpErrors from 'http-errors';
|
|
7
7
|
|
|
8
8
|
export namespace RestHttpErrors {
|
|
9
9
|
export function invalidData<T, Props extends object = {}>(
|
|
@@ -26,10 +26,9 @@ export namespace RestHttpErrors {
|
|
|
26
26
|
contentType: string,
|
|
27
27
|
allowedTypes: string[] = [],
|
|
28
28
|
) {
|
|
29
|
-
const msg =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
: `Content-type ${contentType} is not supported.`;
|
|
29
|
+
const msg = allowedTypes?.length
|
|
30
|
+
? `Content-type ${contentType} does not match [${allowedTypes}].`
|
|
31
|
+
: `Content-type ${contentType} is not supported.`;
|
|
33
32
|
return Object.assign(new HttpErrors.UnsupportedMediaType(msg), {
|
|
34
33
|
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
35
34
|
contentType: contentType,
|
package/src/rest.component.ts
CHANGED
|
@@ -90,7 +90,7 @@ export class RestComponent implements Component {
|
|
|
90
90
|
app.bind(RestBindings.SEQUENCE).toClass(DefaultSequence);
|
|
91
91
|
const apiSpec = createEmptyApiSpec();
|
|
92
92
|
// Merge the OpenAPI `servers` spec from the config into the empty one
|
|
93
|
-
if (config
|
|
93
|
+
if (config?.openApiSpec?.servers) {
|
|
94
94
|
Object.assign(apiSpec, {servers: config.openApiSpec.servers});
|
|
95
95
|
}
|
|
96
96
|
app.bind(RestBindings.API_SPEC).to(apiSpec);
|
package/src/rest.server.ts
CHANGED
|
@@ -21,9 +21,9 @@ import {
|
|
|
21
21
|
ServerObject,
|
|
22
22
|
} from '@loopback/openapi-v3';
|
|
23
23
|
import {AssertionError} from 'assert';
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
24
|
+
import cors from 'cors';
|
|
25
|
+
import debugFactory from 'debug';
|
|
26
|
+
import express from 'express';
|
|
27
27
|
import {PathParams} from 'express-serve-static-core';
|
|
28
28
|
import {IncomingMessage, ServerResponse} from 'http';
|
|
29
29
|
import {ServerOptions} from 'https';
|
|
@@ -74,7 +74,7 @@ export interface HttpServerLike {
|
|
|
74
74
|
|
|
75
75
|
const SequenceActions = RestBindings.SequenceActions;
|
|
76
76
|
|
|
77
|
-
// NOTE(bajtos) we cannot use `import
|
|
77
|
+
// NOTE(bajtos) we cannot use `import cloneDeep from 'lodash/cloneDeep'
|
|
78
78
|
// because it produces the following TypeScript error:
|
|
79
79
|
// Module '"(...)/node_modules/@types/lodash/cloneDeep/index"' resolves to
|
|
80
80
|
// a non-module entity and cannot be imported using this construct.
|
|
@@ -194,7 +194,7 @@ export class RestServer extends Context implements Server, HttpServerLike {
|
|
|
194
194
|
this.bind(RestBindings.PORT).to(this.config.port);
|
|
195
195
|
this.bind(RestBindings.HOST).to(config.host);
|
|
196
196
|
this.bind(RestBindings.PATH).to(config.path);
|
|
197
|
-
this.bind(RestBindings.PROTOCOL).to(config.protocol
|
|
197
|
+
this.bind(RestBindings.PROTOCOL).to(config.protocol ?? 'http');
|
|
198
198
|
this.bind(RestBindings.HTTPS_OPTIONS).to(config as ServerOptions);
|
|
199
199
|
|
|
200
200
|
if (config.requestBodyParser) {
|
|
@@ -424,7 +424,7 @@ export class RestServer extends Context implements Server, HttpServerLike {
|
|
|
424
424
|
this.config,
|
|
425
425
|
);
|
|
426
426
|
|
|
427
|
-
specForm = specForm
|
|
427
|
+
specForm = specForm ?? {version: '3.0.0', format: 'json'};
|
|
428
428
|
const specObj = this.getApiSpec(requestContext);
|
|
429
429
|
|
|
430
430
|
if (specForm.format === 'json') {
|
|
@@ -707,7 +707,7 @@ export class RestServer extends Context implements Server, HttpServerLike {
|
|
|
707
707
|
// accidentally modifying our internal routing data
|
|
708
708
|
spec.paths = cloneDeep(this.httpHandler.describeApiPaths());
|
|
709
709
|
if (defs) {
|
|
710
|
-
spec.components = spec.components
|
|
710
|
+
spec.components = spec.components ?? {};
|
|
711
711
|
spec.components.schemas = cloneDeep(defs);
|
|
712
712
|
}
|
|
713
713
|
|
|
@@ -928,7 +928,7 @@ export function createBodyParserBinding(
|
|
|
928
928
|
key?: BindingAddress<BodyParser>,
|
|
929
929
|
): Binding<BodyParser> {
|
|
930
930
|
const address =
|
|
931
|
-
key
|
|
931
|
+
key ?? `${RestBindings.REQUEST_BODY_PARSER}.${parserClass.name}`;
|
|
932
932
|
return Binding.bind<BodyParser>(address)
|
|
933
933
|
.toClass(parserClass)
|
|
934
934
|
.inScope(BindingScope.TRANSIENT)
|
|
@@ -1093,11 +1093,11 @@ function resolveRestServerConfig(
|
|
|
1093
1093
|
function normalizeApiExplorerConfig(
|
|
1094
1094
|
input: ApiExplorerOptions | undefined,
|
|
1095
1095
|
): ApiExplorerOptions {
|
|
1096
|
-
const config = input
|
|
1097
|
-
const url = config.url
|
|
1096
|
+
const config = input ?? {};
|
|
1097
|
+
const url = config.url ?? 'https://explorer.loopback.io';
|
|
1098
1098
|
|
|
1099
1099
|
config.httpUrl =
|
|
1100
|
-
config.httpUrl
|
|
1100
|
+
config.httpUrl ?? config.url ?? 'http://explorer.loopback.io';
|
|
1101
1101
|
|
|
1102
1102
|
config.url = url;
|
|
1103
1103
|
|