@loopback/express 1.2.5 → 1.4.1
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 +40 -0
- package/dist/group-sorter.d.ts +6 -0
- package/dist/group-sorter.js +37 -0
- package/dist/group-sorter.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/keys.js +2 -1
- package/dist/keys.js.map +1 -1
- package/dist/middleware.d.ts +18 -1
- package/dist/middleware.js +79 -7
- package/dist/middleware.js.map +1 -1
- package/dist/types.d.ts +80 -3
- package/dist/types.js +25 -1
- package/dist/types.js.map +1 -1
- package/package.json +14 -12
- package/src/group-sorter.ts +35 -0
- package/src/index.ts +1 -0
- package/src/keys.ts +2 -2
- package/src/middleware.ts +95 -14
- package/src/types.ts +91 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,46 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.4.1](https://github.com/strongloop/loopback-next/compare/@loopback/express@1.4.0...@loopback/express@1.4.1) (2020-08-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @loopback/express
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [1.4.0](https://github.com/strongloop/loopback-next/compare/@loopback/express@1.3.0...@loopback/express@1.4.0) (2020-08-19)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **express:** add middleware view to watch registered middleware ([205d948](https://github.com/strongloop/loopback-next/commit/205d948cb91cf48d187ce247ee5e77b1204be35e))
|
|
20
|
+
* **rest:** add the ability to validate sorted middleware groups ([227dbf8](https://github.com/strongloop/loopback-next/commit/227dbf8045990536ac1437ea4a7ae1f1a1e571bb))
|
|
21
|
+
* **rest:** optimize middleware sequence to reuse middleware binding keys ([0041a24](https://github.com/strongloop/loopback-next/commit/0041a246df89f7dbff179ed7c5e08a65ec5bcbda))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# [1.3.0](https://github.com/strongloop/loopback-next/compare/@loopback/express@1.2.6...@loopback/express@1.3.0) (2020-08-05)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Features
|
|
31
|
+
|
|
32
|
+
* **express:** sort middleware by group dependencies and ordered groups ([5582f06](https://github.com/strongloop/loopback-next/commit/5582f069834666a6d6a9d8d2f2d66fa1a9a5f7d3))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## [1.2.6](https://github.com/strongloop/loopback-next/compare/@loopback/express@1.2.5...@loopback/express@1.2.6) (2020-07-20)
|
|
39
|
+
|
|
40
|
+
**Note:** Version bump only for package @loopback/express
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
6
46
|
## [1.2.5](https://github.com/strongloop/loopback-next/compare/@loopback/express@1.2.4...@loopback/express@1.2.5) (2020-06-30)
|
|
7
47
|
|
|
8
48
|
**Note:** Version bump only for package @loopback/express
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/express
|
|
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.sortListOfGroups = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
10
|
+
const toposort_1 = tslib_1.__importDefault(require("toposort"));
|
|
11
|
+
const debug = debug_1.default('loopback:middleware');
|
|
12
|
+
/**
|
|
13
|
+
* Sort the groups by their relative order
|
|
14
|
+
* @param orderedGroups - A list of arrays - each of which represents a partial
|
|
15
|
+
* order of groups.
|
|
16
|
+
*/
|
|
17
|
+
function sortListOfGroups(...orderedGroups) {
|
|
18
|
+
if (debug.enabled) {
|
|
19
|
+
debug('Dependency graph: %s', orderedGroups.map(edge => edge.join('->')).join(', '));
|
|
20
|
+
}
|
|
21
|
+
const graph = [];
|
|
22
|
+
for (const groups of orderedGroups) {
|
|
23
|
+
if (groups.length >= 2) {
|
|
24
|
+
groups.reduce((prev, group) => {
|
|
25
|
+
if (typeof prev === 'string') {
|
|
26
|
+
graph.push([prev, group]);
|
|
27
|
+
}
|
|
28
|
+
return group;
|
|
29
|
+
}, undefined);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const sorted = toposort_1.default(graph);
|
|
33
|
+
debug('Sorted groups: %s', sorted.join('->'));
|
|
34
|
+
return sorted;
|
|
35
|
+
}
|
|
36
|
+
exports.sortListOfGroups = sortListOfGroups;
|
|
37
|
+
//# sourceMappingURL=group-sorter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-sorter.js","sourceRoot":"","sources":["../src/group-sorter.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,0DAAiC;AACjC,gEAAgC;AAChC,MAAM,KAAK,GAAG,eAAY,CAAC,qBAAqB,CAAC,CAAC;AAClD;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,GAAG,aAAyB;IAC3D,IAAI,KAAK,CAAC,OAAO,EAAE;QACjB,KAAK,CACH,sBAAsB,EACtB,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACtD,CAAC;KACH;IACD,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE;QAClC,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE;YACtB,MAAM,CAAC,MAAM,CAAC,CAAC,IAAwB,EAAE,KAAK,EAAE,EAAE;gBAChD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;oBAC5B,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;iBAC3B;gBACD,OAAO,KAAK,CAAC;YACf,CAAC,EAAE,SAAS,CAAC,CAAC;SACf;KACF;IACD,MAAM,MAAM,GAAG,kBAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,KAAK,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,OAAO,MAAM,CAAC;AAChB,CAAC;AArBD,4CAqBC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ const tslib_1 = require("tslib");
|
|
|
24
24
|
*/
|
|
25
25
|
tslib_1.__exportStar(require("./express.application"), exports);
|
|
26
26
|
tslib_1.__exportStar(require("./express.server"), exports);
|
|
27
|
+
tslib_1.__exportStar(require("./group-sorter"), exports);
|
|
27
28
|
tslib_1.__exportStar(require("./keys"), exports);
|
|
28
29
|
tslib_1.__exportStar(require("./middleware"), exports);
|
|
29
30
|
tslib_1.__exportStar(require("./middleware-interceptor"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;AAEhE;;;;;;;;;;;;;;;;GAgBG;AACH,gEAAsC;AACtC,2DAAiC;AACjC,iDAAuB;AACvB,uDAA6B;AAC7B,mEAAyC;AACzC,gEAAsC;AACtC,oEAA0C;AAC1C,iFAAuD;AACvD,kDAAwB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;AAEhE;;;;;;;;;;;;;;;;GAgBG;AACH,gEAAsC;AACtC,2DAAiC;AACjC,yDAA+B;AAC/B,iDAAuB;AACvB,uDAA6B;AAC7B,mEAAyC;AACzC,gEAAsC;AACtC,oEAA0C;AAC1C,iFAAuD;AACvD,kDAAwB"}
|
package/dist/keys.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.DEFAULT_MIDDLEWARE_GROUP = exports.MIDDLEWARE_INTERCEPTOR_NAMESPACE = exports.GLOBAL_MIDDLEWARE_INTERCEPTOR_NAMESPACE = exports.MIDDLEWARE_NAMESPACE = exports.MiddlewareBindings = void 0;
|
|
8
8
|
const core_1 = require("@loopback/core");
|
|
9
|
+
const types_1 = require("./types");
|
|
9
10
|
var MiddlewareBindings;
|
|
10
11
|
(function (MiddlewareBindings) {
|
|
11
12
|
/**
|
|
@@ -28,5 +29,5 @@ exports.MIDDLEWARE_INTERCEPTOR_NAMESPACE = 'globalInterceptors.middleware';
|
|
|
28
29
|
/**
|
|
29
30
|
* Default order group name for Express middleware based global interceptors
|
|
30
31
|
*/
|
|
31
|
-
exports.DEFAULT_MIDDLEWARE_GROUP =
|
|
32
|
+
exports.DEFAULT_MIDDLEWARE_GROUP = types_1.MiddlewareGroups.DEFAULT;
|
|
32
33
|
//# sourceMappingURL=keys.js.map
|
package/dist/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAA0C;
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAA0C;AAC1C,mCAA4D;AAE5D,IAAiB,kBAAkB,CAOlC;AAPD,WAAiB,kBAAkB;IACjC;;OAEG;IACU,0BAAO,GAAG,iBAAU,CAAC,MAAM,CACtC,yBAAyB,CAC1B,CAAC;AACJ,CAAC,EAPgB,kBAAkB,GAAlB,0BAAkB,KAAlB,0BAAkB,QAOlC;AAED;;GAEG;AACU,QAAA,oBAAoB,GAAG,YAAY,CAAC;AAEjD;;GAEG;AACU,QAAA,uCAAuC,GAClD,+BAA+B,CAAC;AAElC;;GAEG;AACU,QAAA,gCAAgC,GAAG,+BAA+B,CAAC;AAEhF;;GAEG;AACU,QAAA,wBAAwB,GAAG,wBAAgB,CAAC,OAAO,CAAC"}
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Binding, BindingTemplate, Constructor, Context, InvocationResult, Provider, ValueOrPromise } from '@loopback/core';
|
|
1
|
+
import { Binding, BindingTemplate, Constructor, Context, ContextView, InvocationResult, Provider, ValueOrPromise } from '@loopback/core';
|
|
2
2
|
import { ExpressMiddlewareFactory, ExpressRequestHandler, InvokeMiddlewareOptions, Middleware, MiddlewareBindingOptions, MiddlewareContext } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* An adapter function to create a LoopBack middleware that invokes the list
|
|
@@ -63,6 +63,23 @@ export declare function createMiddlewareBinding(middlewareProviderClass: Constru
|
|
|
63
63
|
* @param options - Options to invoke the middleware chain
|
|
64
64
|
*/
|
|
65
65
|
export declare function invokeMiddleware(middlewareCtx: MiddlewareContext, options?: InvokeMiddlewareOptions): ValueOrPromise<InvocationResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Watch middleware binding keys for the given context and sort them by
|
|
68
|
+
* group
|
|
69
|
+
* @param ctx - Context object
|
|
70
|
+
* @param options - Middleware options
|
|
71
|
+
*/
|
|
72
|
+
export declare class MiddlewareView extends ContextView {
|
|
73
|
+
private options;
|
|
74
|
+
private keys;
|
|
75
|
+
constructor(ctx: Context, options?: InvokeMiddlewareOptions);
|
|
76
|
+
refresh(): void;
|
|
77
|
+
/**
|
|
78
|
+
* A list of binding keys sorted by group for registered middleware
|
|
79
|
+
*/
|
|
80
|
+
get middlewareBindingKeys(): string[];
|
|
81
|
+
private buildMiddlewareKeys;
|
|
82
|
+
}
|
|
66
83
|
/**
|
|
67
84
|
* Invoke a list of Express middleware handler functions
|
|
68
85
|
*
|
package/dist/middleware.js
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
// This file is licensed under the MIT License.
|
|
5
5
|
// License text available at https://opensource.org/licenses/MIT
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.toExpressMiddleware = exports.invokeExpressMiddleware = exports.invokeMiddleware = exports.createMiddlewareBinding = exports.registerMiddleware = exports.asMiddleware = exports.registerExpressMiddleware = exports.createMiddleware = exports.toMiddleware = void 0;
|
|
7
|
+
exports.toExpressMiddleware = exports.invokeExpressMiddleware = exports.MiddlewareView = exports.invokeMiddleware = exports.createMiddlewareBinding = exports.registerMiddleware = exports.asMiddleware = exports.registerExpressMiddleware = exports.createMiddleware = exports.toMiddleware = void 0;
|
|
8
8
|
const tslib_1 = require("tslib");
|
|
9
9
|
const core_1 = require("@loopback/core");
|
|
10
10
|
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
11
|
+
const group_sorter_1 = require("./group-sorter");
|
|
11
12
|
const keys_1 = require("./keys");
|
|
12
13
|
const middleware_interceptor_1 = require("./middleware-interceptor");
|
|
13
14
|
const types_1 = require("./types");
|
|
@@ -84,6 +85,18 @@ function asMiddleware(options = {}) {
|
|
|
84
85
|
binding
|
|
85
86
|
.apply(core_1.extensionFor((_a = options.chain) !== null && _a !== void 0 ? _a : types_1.DEFAULT_MIDDLEWARE_CHAIN))
|
|
86
87
|
.tag({ group: (_b = options.group) !== null && _b !== void 0 ? _b : keys_1.DEFAULT_MIDDLEWARE_GROUP });
|
|
88
|
+
const groupsBefore = options.upstreamGroups;
|
|
89
|
+
if (groupsBefore != null) {
|
|
90
|
+
binding.tag({
|
|
91
|
+
upstreamGroups: typeof groupsBefore === 'string' ? [groupsBefore] : groupsBefore,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const groupsAfter = options.downstreamGroups;
|
|
95
|
+
if (groupsAfter != null) {
|
|
96
|
+
binding.tag({
|
|
97
|
+
downstreamGroups: typeof groupsAfter === 'string' ? [groupsAfter] : groupsAfter,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
87
100
|
};
|
|
88
101
|
}
|
|
89
102
|
exports.asMiddleware = asMiddleware;
|
|
@@ -134,16 +147,75 @@ exports.createMiddlewareBinding = createMiddlewareBinding;
|
|
|
134
147
|
*/
|
|
135
148
|
function invokeMiddleware(middlewareCtx, options) {
|
|
136
149
|
debug('Invoke middleware chain for %s %s with options', middlewareCtx.request.method, middlewareCtx.request.originalUrl, options);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
150
|
+
let keys = options === null || options === void 0 ? void 0 : options.middlewareList;
|
|
151
|
+
if (keys == null) {
|
|
152
|
+
const view = new MiddlewareView(middlewareCtx, options);
|
|
153
|
+
keys = view.middlewareBindingKeys;
|
|
154
|
+
view.close();
|
|
142
155
|
}
|
|
143
|
-
const mwChain = new types_1.MiddlewareChain(middlewareCtx,
|
|
156
|
+
const mwChain = new types_1.MiddlewareChain(middlewareCtx, keys);
|
|
144
157
|
return mwChain.invokeInterceptors(options === null || options === void 0 ? void 0 : options.next);
|
|
145
158
|
}
|
|
146
159
|
exports.invokeMiddleware = invokeMiddleware;
|
|
160
|
+
/**
|
|
161
|
+
* Watch middleware binding keys for the given context and sort them by
|
|
162
|
+
* group
|
|
163
|
+
* @param ctx - Context object
|
|
164
|
+
* @param options - Middleware options
|
|
165
|
+
*/
|
|
166
|
+
class MiddlewareView extends core_1.ContextView {
|
|
167
|
+
constructor(ctx, options) {
|
|
168
|
+
var _a;
|
|
169
|
+
// Find extensions for the given extension point binding
|
|
170
|
+
const filter = core_1.extensionFilter((_a = options === null || options === void 0 ? void 0 : options.chain) !== null && _a !== void 0 ? _a : types_1.DEFAULT_MIDDLEWARE_CHAIN);
|
|
171
|
+
super(ctx, filter);
|
|
172
|
+
this.options = {
|
|
173
|
+
chain: types_1.DEFAULT_MIDDLEWARE_CHAIN,
|
|
174
|
+
orderedGroups: [],
|
|
175
|
+
...options,
|
|
176
|
+
};
|
|
177
|
+
this.buildMiddlewareKeys();
|
|
178
|
+
this.open();
|
|
179
|
+
}
|
|
180
|
+
refresh() {
|
|
181
|
+
super.refresh();
|
|
182
|
+
this.buildMiddlewareKeys();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* A list of binding keys sorted by group for registered middleware
|
|
186
|
+
*/
|
|
187
|
+
get middlewareBindingKeys() {
|
|
188
|
+
return this.keys;
|
|
189
|
+
}
|
|
190
|
+
buildMiddlewareKeys() {
|
|
191
|
+
var _a;
|
|
192
|
+
const middlewareBindings = this.bindings;
|
|
193
|
+
if (debug.enabled) {
|
|
194
|
+
debug('Middleware for extension point "%s":', this.options.chain, middlewareBindings.map(b => b.key));
|
|
195
|
+
}
|
|
196
|
+
// Calculate orders from middleware dependencies
|
|
197
|
+
const ordersFromDependencies = [];
|
|
198
|
+
middlewareBindings.forEach(b => {
|
|
199
|
+
var _a, _b, _c;
|
|
200
|
+
const group = (_a = b.tagMap.group) !== null && _a !== void 0 ? _a : keys_1.DEFAULT_MIDDLEWARE_GROUP;
|
|
201
|
+
const groupsBefore = (_b = b.tagMap.upstreamGroups) !== null && _b !== void 0 ? _b : [];
|
|
202
|
+
groupsBefore.forEach(d => ordersFromDependencies.push([d, group]));
|
|
203
|
+
const groupsAfter = (_c = b.tagMap.downstreamGroups) !== null && _c !== void 0 ? _c : [];
|
|
204
|
+
groupsAfter.forEach(d => ordersFromDependencies.push([group, d]));
|
|
205
|
+
});
|
|
206
|
+
const order = group_sorter_1.sortListOfGroups(...ordersFromDependencies, this.options.orderedGroups);
|
|
207
|
+
/**
|
|
208
|
+
* Validate sorted groups
|
|
209
|
+
*/
|
|
210
|
+
if (typeof ((_a = this.options) === null || _a === void 0 ? void 0 : _a.validate) === 'function') {
|
|
211
|
+
this.options.validate(order);
|
|
212
|
+
}
|
|
213
|
+
this.keys = middlewareBindings
|
|
214
|
+
.sort(core_1.compareBindingsByTag('group', order))
|
|
215
|
+
.map(b => b.key);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.MiddlewareView = MiddlewareView;
|
|
147
219
|
/**
|
|
148
220
|
* Invoke a list of Express middleware handler functions
|
|
149
221
|
*
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BindingAddress, Context, GenericInterceptor, GenericInterceptorChain, InvocationContext, Next, ValueOrPromise } from '@loopback/core';
|
|
1
|
+
import { BindingAddress, Context, GenericInterceptor, GenericInterceptorChain, GenericInterceptorOrKey, InvocationContext, Next, ValueOrPromise } from '@loopback/core';
|
|
2
2
|
import { Request, RequestHandler, Response } from 'express';
|
|
3
3
|
export { Request, Response, Router, RouterOptions } from 'express';
|
|
4
4
|
/**
|
|
@@ -20,6 +20,10 @@ export declare type ExpressRequestHandler = RequestHandler;
|
|
|
20
20
|
export declare class MiddlewareContext extends Context implements HandlerContext {
|
|
21
21
|
readonly request: Request;
|
|
22
22
|
readonly response: Response;
|
|
23
|
+
/**
|
|
24
|
+
* A flag to tell if the response is finished.
|
|
25
|
+
*/
|
|
26
|
+
responseFinished: boolean;
|
|
23
27
|
/**
|
|
24
28
|
* Constructor for `MiddlewareContext`
|
|
25
29
|
* @param request - Express request object
|
|
@@ -33,7 +37,28 @@ export declare class MiddlewareContext extends Context implements HandlerContext
|
|
|
33
37
|
/**
|
|
34
38
|
* Interface LoopBack 4 middleware to be executed within sequence of actions.
|
|
35
39
|
* A middleware for LoopBack is basically a generic interceptor that uses
|
|
36
|
-
* `
|
|
40
|
+
* `MiddlewareContext`.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
*
|
|
44
|
+
* The middleware function is responsible for processing HTTP requests and
|
|
45
|
+
* responses. It typically includes the following logic.
|
|
46
|
+
*
|
|
47
|
+
* 1. Process the request with one of the following outcome
|
|
48
|
+
* - Reject the request by throwing an error if request is invalid, such as
|
|
49
|
+
* validation or authentication failures
|
|
50
|
+
* - Produce a response by itself, such as from the cache
|
|
51
|
+
* - Proceed by calling `await next()` to invoke downstream middleware. When
|
|
52
|
+
* `await next()` returns, it goes to step 2. If an error thrown from
|
|
53
|
+
* `await next()`, step 3 handles the error.
|
|
54
|
+
*
|
|
55
|
+
* 2. Process the response with one the following outcome
|
|
56
|
+
* - Reject the response by throwing an error
|
|
57
|
+
* - Replace the response with its own value
|
|
58
|
+
* - Return the response to upstream middleware
|
|
59
|
+
*
|
|
60
|
+
* 3. Catch the error thrown from `await next()`. If the `catch` block does not
|
|
61
|
+
* exist, the error will be bubbled up to upstream middleware
|
|
37
62
|
*
|
|
38
63
|
* The signature of a middleware function is described at
|
|
39
64
|
* {@link https://loopback.io/doc/en/lb4/apidocs.express.middleware.html | Middleware}.
|
|
@@ -64,6 +89,10 @@ export interface Middleware extends GenericInterceptor<MiddlewareContext> {
|
|
|
64
89
|
*/
|
|
65
90
|
export declare class MiddlewareChain extends GenericInterceptorChain<MiddlewareContext> {
|
|
66
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* A middleware function or binding key
|
|
94
|
+
*/
|
|
95
|
+
export declare type MiddlewareOrKey = GenericInterceptorOrKey<MiddlewareContext>;
|
|
67
96
|
/**
|
|
68
97
|
* Default extension point name for middleware
|
|
69
98
|
*/
|
|
@@ -78,9 +107,23 @@ export interface InvokeMiddlewareOptions {
|
|
|
78
107
|
*/
|
|
79
108
|
chain?: string;
|
|
80
109
|
/**
|
|
81
|
-
* An array of group names to denote the order of execution
|
|
110
|
+
* An array of group names to denote the order of execution, such as
|
|
111
|
+
* `['cors', 'caching', 'rate-limiting']`.
|
|
82
112
|
*/
|
|
83
113
|
orderedGroups?: string[];
|
|
114
|
+
/**
|
|
115
|
+
* An optional function to validate the sorted groups before invoking the
|
|
116
|
+
* middleware chain
|
|
117
|
+
*/
|
|
118
|
+
validate?: (groups: string[]) => void;
|
|
119
|
+
/**
|
|
120
|
+
* Pre-built middleware list. If set, the list will be used to create the
|
|
121
|
+
* middleware chain without discovering again within the context.
|
|
122
|
+
*/
|
|
123
|
+
middlewareList?: MiddlewareOrKey[];
|
|
124
|
+
/**
|
|
125
|
+
* Optional next handler
|
|
126
|
+
*/
|
|
84
127
|
next?: Next;
|
|
85
128
|
}
|
|
86
129
|
/**
|
|
@@ -173,6 +216,22 @@ export interface MiddlewareBindingOptions extends BaseMiddlewareBindingOptions<M
|
|
|
173
216
|
* Name of the middleware extension point. Default to `DEFAULT_MIDDLEWARE_CHAIN`.
|
|
174
217
|
*/
|
|
175
218
|
chain?: string;
|
|
219
|
+
/**
|
|
220
|
+
* An array of group names for upstream middleware in the cascading order.
|
|
221
|
+
*
|
|
222
|
+
* For example, the `invokeMethod` depends on `parseParams` for request
|
|
223
|
+
* processing. The `upstreamGroups` for `invokeMethod` should be
|
|
224
|
+
* `['parseParams']`. The order of groups in the array does not matter.
|
|
225
|
+
*/
|
|
226
|
+
upstreamGroups?: string | string[];
|
|
227
|
+
/**
|
|
228
|
+
* An array of group names for downstream middleware in the cascading order.
|
|
229
|
+
*
|
|
230
|
+
* For example, the `sendResponse` depends on `invokeMethod` for response
|
|
231
|
+
* processing. The `downstreamGroups` for `sendResponse` should be
|
|
232
|
+
* `['invokeMethod']`. The order of groups in the array does not matter.
|
|
233
|
+
*/
|
|
234
|
+
downstreamGroups?: string | string[];
|
|
176
235
|
}
|
|
177
236
|
/**
|
|
178
237
|
* Interface for an express middleware factory
|
|
@@ -185,3 +244,21 @@ export interface ExpressMiddlewareFactory<C> {
|
|
|
185
244
|
* A symbol to store `MiddlewareContext` on the request object
|
|
186
245
|
*/
|
|
187
246
|
export declare const MIDDLEWARE_CONTEXT: unique symbol;
|
|
247
|
+
/**
|
|
248
|
+
* Constants for middleware groups
|
|
249
|
+
*/
|
|
250
|
+
export declare namespace MiddlewareGroups {
|
|
251
|
+
/**
|
|
252
|
+
* Enforce CORS
|
|
253
|
+
*/
|
|
254
|
+
const CORS = "cors";
|
|
255
|
+
/**
|
|
256
|
+
* Server OpenAPI specs
|
|
257
|
+
*/
|
|
258
|
+
const API_SPEC = "apiSpec";
|
|
259
|
+
/**
|
|
260
|
+
* Default middleware group
|
|
261
|
+
*/
|
|
262
|
+
const MIDDLEWARE = "middleware";
|
|
263
|
+
const DEFAULT = "middleware";
|
|
264
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// This file is licensed under the MIT License.
|
|
5
5
|
// License text available at https://opensource.org/licenses/MIT
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.MIDDLEWARE_CONTEXT = exports.DEFAULT_MIDDLEWARE_CHAIN = exports.MiddlewareChain = exports.MiddlewareContext = void 0;
|
|
7
|
+
exports.MiddlewareGroups = exports.MIDDLEWARE_CONTEXT = exports.DEFAULT_MIDDLEWARE_CHAIN = exports.MiddlewareChain = exports.MiddlewareContext = exports.Router = void 0;
|
|
8
8
|
const tslib_1 = require("tslib");
|
|
9
9
|
const core_1 = require("@loopback/core");
|
|
10
10
|
const on_finished_1 = tslib_1.__importDefault(require("on-finished"));
|
|
@@ -27,8 +27,13 @@ class MiddlewareContext extends core_1.Context {
|
|
|
27
27
|
super(parent, name);
|
|
28
28
|
this.request = request;
|
|
29
29
|
this.response = response;
|
|
30
|
+
/**
|
|
31
|
+
* A flag to tell if the response is finished.
|
|
32
|
+
*/
|
|
33
|
+
this.responseFinished = false;
|
|
30
34
|
this.setupBindings();
|
|
31
35
|
on_finished_1.default(this.response, () => {
|
|
36
|
+
this.responseFinished = true;
|
|
32
37
|
// Close the request context when the http response is finished so that
|
|
33
38
|
// it can be recycled by GC
|
|
34
39
|
this.emit('close');
|
|
@@ -55,4 +60,23 @@ exports.DEFAULT_MIDDLEWARE_CHAIN = 'middlewareChain.default';
|
|
|
55
60
|
* A symbol to store `MiddlewareContext` on the request object
|
|
56
61
|
*/
|
|
57
62
|
exports.MIDDLEWARE_CONTEXT = Symbol('loopback.middleware.context');
|
|
63
|
+
/**
|
|
64
|
+
* Constants for middleware groups
|
|
65
|
+
*/
|
|
66
|
+
var MiddlewareGroups;
|
|
67
|
+
(function (MiddlewareGroups) {
|
|
68
|
+
/**
|
|
69
|
+
* Enforce CORS
|
|
70
|
+
*/
|
|
71
|
+
MiddlewareGroups.CORS = 'cors';
|
|
72
|
+
/**
|
|
73
|
+
* Server OpenAPI specs
|
|
74
|
+
*/
|
|
75
|
+
MiddlewareGroups.API_SPEC = 'apiSpec';
|
|
76
|
+
/**
|
|
77
|
+
* Default middleware group
|
|
78
|
+
*/
|
|
79
|
+
MiddlewareGroups.MIDDLEWARE = 'middleware';
|
|
80
|
+
MiddlewareGroups.DEFAULT = MiddlewareGroups.MIDDLEWARE;
|
|
81
|
+
})(MiddlewareGroups = exports.MiddlewareGroups || (exports.MiddlewareGroups = {}));
|
|
58
82
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,iCAAiC;AACjC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,yCASwB;AAExB,sEAAqC;AACrC,iCAA0C;AAE1C,mCAAiE;AAAtC,iGAAA,MAAM,OAAA;AAgBjC;;;GAGG;AACH,MAAa,iBAAkB,SAAQ,cAAO;IAM5C;;;;;;OAMG;IACH,YACkB,OAAgB,EAChB,QAAkB,EAClC,MAAgB,EAChB,IAAa;QAEb,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QALJ,YAAO,GAAP,OAAO,CAAS;QAChB,aAAQ,GAAR,QAAQ,CAAU;QAdpC;;WAEG;QACH,qBAAgB,GAAG,KAAK,CAAC;QAgBvB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,qBAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC7B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,uEAAuE;YACvE,2BAA2B;YAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAES,aAAa;QACrB,IAAI,CAAC,IAAI,CAAC,yBAAkB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,CAAC;CACF;AAjCD,8CAiCC;AAmDD;;;GAGG;AACH,MAAa,eAAgB,SAAQ,8BAEpC;CAAG;AAFJ,0CAEI;AAOJ;;GAEG;AACU,QAAA,wBAAwB,GAAG,yBAAyB,CAAC;AAwKlE;;GAEG;AACU,QAAA,kBAAkB,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;AAExE;;GAEG;AACH,IAAiB,gBAAgB,CAgBhC;AAhBD,WAAiB,gBAAgB;IAC/B;;OAEG;IACU,qBAAI,GAAG,MAAM,CAAC;IAE3B;;OAEG;IACU,yBAAQ,GAAG,SAAS,CAAC;IAElC;;OAEG;IACU,2BAAU,GAAG,YAAY,CAAC;IAC1B,wBAAO,GAAG,iBAAA,UAAU,CAAC;AACpC,CAAC,EAhBgB,gBAAgB,GAAhB,wBAAgB,KAAhB,wBAAgB,QAgBhC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopback/express",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Integrate with Express and expose middleware infrastructure for sequence and interceptors",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,28 +37,30 @@
|
|
|
37
37
|
"!*/__tests__"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@loopback/core": "^2.9.
|
|
41
|
-
"@loopback/http-server": "^2.
|
|
40
|
+
"@loopback/core": "^2.9.5",
|
|
41
|
+
"@loopback/http-server": "^2.2.0",
|
|
42
42
|
"@types/body-parser": "^1.19.0",
|
|
43
|
-
"@types/express": "^4.17.
|
|
44
|
-
"@types/express-serve-static-core": "^4.17.
|
|
45
|
-
"@types/http-errors": "^1.
|
|
43
|
+
"@types/express": "^4.17.7",
|
|
44
|
+
"@types/express-serve-static-core": "^4.17.9",
|
|
45
|
+
"@types/http-errors": "^1.8.0",
|
|
46
46
|
"body-parser": "^1.19.0",
|
|
47
47
|
"debug": "^4.1.1",
|
|
48
48
|
"express": "^4.17.1",
|
|
49
49
|
"http-errors": "^1.8.0",
|
|
50
50
|
"on-finished": "^2.3.0",
|
|
51
|
-
"
|
|
51
|
+
"toposort": "^2.0.2",
|
|
52
|
+
"tslib": "^2.0.1"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"@loopback/build": "^6.
|
|
55
|
-
"@loopback/testlab": "^3.2.
|
|
55
|
+
"@loopback/build": "^6.2.2",
|
|
56
|
+
"@loopback/testlab": "^3.2.4",
|
|
56
57
|
"@types/debug": "^4.1.5",
|
|
57
|
-
"@types/node": "^10.17.
|
|
58
|
+
"@types/node": "^10.17.28",
|
|
58
59
|
"@types/on-finished": "^2.3.1",
|
|
60
|
+
"@types/toposort": "^2.0.3",
|
|
59
61
|
"http-errors": "^1.8.0",
|
|
60
62
|
"source-map-support": "^0.5.19",
|
|
61
|
-
"typescript": "~
|
|
63
|
+
"typescript": "~4.0.2"
|
|
62
64
|
},
|
|
63
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "a3f54273814de63819e0d8bc86509f8a737800bb"
|
|
64
66
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/express
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import debugFactory from 'debug';
|
|
7
|
+
import toposort from 'toposort';
|
|
8
|
+
const debug = debugFactory('loopback:middleware');
|
|
9
|
+
/**
|
|
10
|
+
* Sort the groups by their relative order
|
|
11
|
+
* @param orderedGroups - A list of arrays - each of which represents a partial
|
|
12
|
+
* order of groups.
|
|
13
|
+
*/
|
|
14
|
+
export function sortListOfGroups(...orderedGroups: string[][]) {
|
|
15
|
+
if (debug.enabled) {
|
|
16
|
+
debug(
|
|
17
|
+
'Dependency graph: %s',
|
|
18
|
+
orderedGroups.map(edge => edge.join('->')).join(', '),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
const graph: [string, string][] = [];
|
|
22
|
+
for (const groups of orderedGroups) {
|
|
23
|
+
if (groups.length >= 2) {
|
|
24
|
+
groups.reduce((prev: string | undefined, group) => {
|
|
25
|
+
if (typeof prev === 'string') {
|
|
26
|
+
graph.push([prev, group]);
|
|
27
|
+
}
|
|
28
|
+
return group;
|
|
29
|
+
}, undefined);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const sorted = toposort(graph);
|
|
33
|
+
debug('Sorted groups: %s', sorted.join('->'));
|
|
34
|
+
return sorted;
|
|
35
|
+
}
|
package/src/index.ts
CHANGED
package/src/keys.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
import {BindingKey} from '@loopback/core';
|
|
7
|
-
import {MiddlewareContext} from './types';
|
|
7
|
+
import {MiddlewareContext, MiddlewareGroups} from './types';
|
|
8
8
|
|
|
9
9
|
export namespace MiddlewareBindings {
|
|
10
10
|
/**
|
|
@@ -34,4 +34,4 @@ export const MIDDLEWARE_INTERCEPTOR_NAMESPACE = 'globalInterceptors.middleware';
|
|
|
34
34
|
/**
|
|
35
35
|
* Default order group name for Express middleware based global interceptors
|
|
36
36
|
*/
|
|
37
|
-
export const DEFAULT_MIDDLEWARE_GROUP =
|
|
37
|
+
export const DEFAULT_MIDDLEWARE_GROUP = MiddlewareGroups.DEFAULT;
|
package/src/middleware.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
compareBindingsByTag,
|
|
12
12
|
Constructor,
|
|
13
13
|
Context,
|
|
14
|
+
ContextView,
|
|
14
15
|
createBindingFromClass,
|
|
15
16
|
extensionFilter,
|
|
16
17
|
extensionFor,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
ValueOrPromise,
|
|
22
23
|
} from '@loopback/core';
|
|
23
24
|
import debugFactory from 'debug';
|
|
25
|
+
import {sortListOfGroups} from './group-sorter';
|
|
24
26
|
import {DEFAULT_MIDDLEWARE_GROUP, MIDDLEWARE_NAMESPACE} from './keys';
|
|
25
27
|
import {
|
|
26
28
|
createInterceptor,
|
|
@@ -133,6 +135,20 @@ export function asMiddleware(
|
|
|
133
135
|
binding
|
|
134
136
|
.apply(extensionFor(options.chain ?? DEFAULT_MIDDLEWARE_CHAIN))
|
|
135
137
|
.tag({group: options.group ?? DEFAULT_MIDDLEWARE_GROUP});
|
|
138
|
+
const groupsBefore = options.upstreamGroups;
|
|
139
|
+
if (groupsBefore != null) {
|
|
140
|
+
binding.tag({
|
|
141
|
+
upstreamGroups:
|
|
142
|
+
typeof groupsBefore === 'string' ? [groupsBefore] : groupsBefore,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const groupsAfter = options.downstreamGroups;
|
|
146
|
+
if (groupsAfter != null) {
|
|
147
|
+
binding.tag({
|
|
148
|
+
downstreamGroups:
|
|
149
|
+
typeof groupsAfter === 'string' ? [groupsAfter] : groupsAfter,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
136
152
|
};
|
|
137
153
|
}
|
|
138
154
|
|
|
@@ -199,24 +215,89 @@ export function invokeMiddleware(
|
|
|
199
215
|
middlewareCtx.request.originalUrl,
|
|
200
216
|
options,
|
|
201
217
|
);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
'Middleware for extension point "%s":',
|
|
208
|
-
chain,
|
|
209
|
-
middlewareCtx.find(filter).map(b => b.key),
|
|
210
|
-
);
|
|
218
|
+
let keys = options?.middlewareList;
|
|
219
|
+
if (keys == null) {
|
|
220
|
+
const view = new MiddlewareView(middlewareCtx, options);
|
|
221
|
+
keys = view.middlewareBindingKeys;
|
|
222
|
+
view.close();
|
|
211
223
|
}
|
|
212
|
-
const mwChain = new MiddlewareChain(
|
|
213
|
-
middlewareCtx,
|
|
214
|
-
filter,
|
|
215
|
-
compareBindingsByTag('group', orderedGroups),
|
|
216
|
-
);
|
|
224
|
+
const mwChain = new MiddlewareChain(middlewareCtx, keys);
|
|
217
225
|
return mwChain.invokeInterceptors(options?.next);
|
|
218
226
|
}
|
|
219
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Watch middleware binding keys for the given context and sort them by
|
|
230
|
+
* group
|
|
231
|
+
* @param ctx - Context object
|
|
232
|
+
* @param options - Middleware options
|
|
233
|
+
*/
|
|
234
|
+
export class MiddlewareView extends ContextView {
|
|
235
|
+
private options: InvokeMiddlewareOptions;
|
|
236
|
+
private keys: string[];
|
|
237
|
+
|
|
238
|
+
constructor(ctx: Context, options?: InvokeMiddlewareOptions) {
|
|
239
|
+
// Find extensions for the given extension point binding
|
|
240
|
+
const filter = extensionFilter(options?.chain ?? DEFAULT_MIDDLEWARE_CHAIN);
|
|
241
|
+
super(ctx, filter);
|
|
242
|
+
this.options = {
|
|
243
|
+
chain: DEFAULT_MIDDLEWARE_CHAIN,
|
|
244
|
+
orderedGroups: [],
|
|
245
|
+
...options,
|
|
246
|
+
};
|
|
247
|
+
this.buildMiddlewareKeys();
|
|
248
|
+
this.open();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
refresh() {
|
|
252
|
+
super.refresh();
|
|
253
|
+
this.buildMiddlewareKeys();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* A list of binding keys sorted by group for registered middleware
|
|
258
|
+
*/
|
|
259
|
+
get middlewareBindingKeys() {
|
|
260
|
+
return this.keys;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private buildMiddlewareKeys() {
|
|
264
|
+
const middlewareBindings = this.bindings;
|
|
265
|
+
if (debug.enabled) {
|
|
266
|
+
debug(
|
|
267
|
+
'Middleware for extension point "%s":',
|
|
268
|
+
this.options.chain,
|
|
269
|
+
middlewareBindings.map(b => b.key),
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Calculate orders from middleware dependencies
|
|
274
|
+
const ordersFromDependencies: string[][] = [];
|
|
275
|
+
middlewareBindings.forEach(b => {
|
|
276
|
+
const group: string = b.tagMap.group ?? DEFAULT_MIDDLEWARE_GROUP;
|
|
277
|
+
const groupsBefore: string[] = b.tagMap.upstreamGroups ?? [];
|
|
278
|
+
groupsBefore.forEach(d => ordersFromDependencies.push([d, group]));
|
|
279
|
+
const groupsAfter: string[] = b.tagMap.downstreamGroups ?? [];
|
|
280
|
+
groupsAfter.forEach(d => ordersFromDependencies.push([group, d]));
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const order = sortListOfGroups(
|
|
284
|
+
...ordersFromDependencies,
|
|
285
|
+
this.options.orderedGroups!,
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Validate sorted groups
|
|
290
|
+
*/
|
|
291
|
+
if (typeof this.options?.validate === 'function') {
|
|
292
|
+
this.options.validate(order);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
this.keys = middlewareBindings
|
|
296
|
+
.sort(compareBindingsByTag('group', order))
|
|
297
|
+
.map(b => b.key);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
220
301
|
/**
|
|
221
302
|
* Invoke a list of Express middleware handler functions
|
|
222
303
|
*
|
package/src/types.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Context,
|
|
9
9
|
GenericInterceptor,
|
|
10
10
|
GenericInterceptorChain,
|
|
11
|
+
GenericInterceptorOrKey,
|
|
11
12
|
InvocationContext,
|
|
12
13
|
Next,
|
|
13
14
|
ValueOrPromise,
|
|
@@ -37,6 +38,11 @@ export type ExpressRequestHandler = RequestHandler;
|
|
|
37
38
|
* context (request, response, etc.).
|
|
38
39
|
*/
|
|
39
40
|
export class MiddlewareContext extends Context implements HandlerContext {
|
|
41
|
+
/**
|
|
42
|
+
* A flag to tell if the response is finished.
|
|
43
|
+
*/
|
|
44
|
+
responseFinished = false;
|
|
45
|
+
|
|
40
46
|
/**
|
|
41
47
|
* Constructor for `MiddlewareContext`
|
|
42
48
|
* @param request - Express request object
|
|
@@ -53,6 +59,7 @@ export class MiddlewareContext extends Context implements HandlerContext {
|
|
|
53
59
|
super(parent, name);
|
|
54
60
|
this.setupBindings();
|
|
55
61
|
onFinished(this.response, () => {
|
|
62
|
+
this.responseFinished = true;
|
|
56
63
|
// Close the request context when the http response is finished so that
|
|
57
64
|
// it can be recycled by GC
|
|
58
65
|
this.emit('close');
|
|
@@ -68,7 +75,28 @@ export class MiddlewareContext extends Context implements HandlerContext {
|
|
|
68
75
|
/**
|
|
69
76
|
* Interface LoopBack 4 middleware to be executed within sequence of actions.
|
|
70
77
|
* A middleware for LoopBack is basically a generic interceptor that uses
|
|
71
|
-
* `
|
|
78
|
+
* `MiddlewareContext`.
|
|
79
|
+
*
|
|
80
|
+
* @remarks
|
|
81
|
+
*
|
|
82
|
+
* The middleware function is responsible for processing HTTP requests and
|
|
83
|
+
* responses. It typically includes the following logic.
|
|
84
|
+
*
|
|
85
|
+
* 1. Process the request with one of the following outcome
|
|
86
|
+
* - Reject the request by throwing an error if request is invalid, such as
|
|
87
|
+
* validation or authentication failures
|
|
88
|
+
* - Produce a response by itself, such as from the cache
|
|
89
|
+
* - Proceed by calling `await next()` to invoke downstream middleware. When
|
|
90
|
+
* `await next()` returns, it goes to step 2. If an error thrown from
|
|
91
|
+
* `await next()`, step 3 handles the error.
|
|
92
|
+
*
|
|
93
|
+
* 2. Process the response with one the following outcome
|
|
94
|
+
* - Reject the response by throwing an error
|
|
95
|
+
* - Replace the response with its own value
|
|
96
|
+
* - Return the response to upstream middleware
|
|
97
|
+
*
|
|
98
|
+
* 3. Catch the error thrown from `await next()`. If the `catch` block does not
|
|
99
|
+
* exist, the error will be bubbled up to upstream middleware
|
|
72
100
|
*
|
|
73
101
|
* The signature of a middleware function is described at
|
|
74
102
|
* {@link https://loopback.io/doc/en/lb4/apidocs.express.middleware.html | Middleware}.
|
|
@@ -101,6 +129,11 @@ export class MiddlewareChain extends GenericInterceptorChain<
|
|
|
101
129
|
MiddlewareContext
|
|
102
130
|
> {}
|
|
103
131
|
|
|
132
|
+
/**
|
|
133
|
+
* A middleware function or binding key
|
|
134
|
+
*/
|
|
135
|
+
export type MiddlewareOrKey = GenericInterceptorOrKey<MiddlewareContext>;
|
|
136
|
+
|
|
104
137
|
/**
|
|
105
138
|
* Default extension point name for middleware
|
|
106
139
|
*/
|
|
@@ -115,11 +148,28 @@ export interface InvokeMiddlewareOptions {
|
|
|
115
148
|
* from the binding
|
|
116
149
|
*/
|
|
117
150
|
chain?: string;
|
|
151
|
+
|
|
118
152
|
/**
|
|
119
|
-
* An array of group names to denote the order of execution
|
|
153
|
+
* An array of group names to denote the order of execution, such as
|
|
154
|
+
* `['cors', 'caching', 'rate-limiting']`.
|
|
120
155
|
*/
|
|
121
156
|
orderedGroups?: string[];
|
|
122
157
|
|
|
158
|
+
/**
|
|
159
|
+
* An optional function to validate the sorted groups before invoking the
|
|
160
|
+
* middleware chain
|
|
161
|
+
*/
|
|
162
|
+
validate?: (groups: string[]) => void;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Pre-built middleware list. If set, the list will be used to create the
|
|
166
|
+
* middleware chain without discovering again within the context.
|
|
167
|
+
*/
|
|
168
|
+
middlewareList?: MiddlewareOrKey[];
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Optional next handler
|
|
172
|
+
*/
|
|
123
173
|
next?: Next;
|
|
124
174
|
}
|
|
125
175
|
|
|
@@ -227,6 +277,24 @@ export interface MiddlewareBindingOptions
|
|
|
227
277
|
* Name of the middleware extension point. Default to `DEFAULT_MIDDLEWARE_CHAIN`.
|
|
228
278
|
*/
|
|
229
279
|
chain?: string;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* An array of group names for upstream middleware in the cascading order.
|
|
283
|
+
*
|
|
284
|
+
* For example, the `invokeMethod` depends on `parseParams` for request
|
|
285
|
+
* processing. The `upstreamGroups` for `invokeMethod` should be
|
|
286
|
+
* `['parseParams']`. The order of groups in the array does not matter.
|
|
287
|
+
*/
|
|
288
|
+
upstreamGroups?: string | string[];
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* An array of group names for downstream middleware in the cascading order.
|
|
292
|
+
*
|
|
293
|
+
* For example, the `sendResponse` depends on `invokeMethod` for response
|
|
294
|
+
* processing. The `downstreamGroups` for `sendResponse` should be
|
|
295
|
+
* `['invokeMethod']`. The order of groups in the array does not matter.
|
|
296
|
+
*/
|
|
297
|
+
downstreamGroups?: string | string[];
|
|
230
298
|
}
|
|
231
299
|
|
|
232
300
|
/**
|
|
@@ -241,3 +309,24 @@ export interface ExpressMiddlewareFactory<C> {
|
|
|
241
309
|
* A symbol to store `MiddlewareContext` on the request object
|
|
242
310
|
*/
|
|
243
311
|
export const MIDDLEWARE_CONTEXT = Symbol('loopback.middleware.context');
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Constants for middleware groups
|
|
315
|
+
*/
|
|
316
|
+
export namespace MiddlewareGroups {
|
|
317
|
+
/**
|
|
318
|
+
* Enforce CORS
|
|
319
|
+
*/
|
|
320
|
+
export const CORS = 'cors';
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Server OpenAPI specs
|
|
324
|
+
*/
|
|
325
|
+
export const API_SPEC = 'apiSpec';
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Default middleware group
|
|
329
|
+
*/
|
|
330
|
+
export const MIDDLEWARE = 'middleware';
|
|
331
|
+
export const DEFAULT = MIDDLEWARE;
|
|
332
|
+
}
|