From 537f21b8c57a6e9a53914a649b95f848c12c3374 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 6 Mar 2019 15:09:23 -0800 Subject: [PATCH] feat(rest): use @loopback/express-middleware to manage express middleware --- packages/rest/package.json | 1 + packages/rest/src/keys.ts | 21 +++++------ packages/rest/src/rest.server.ts | 62 ++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/packages/rest/package.json b/packages/rest/package.json index af7ee00847e9..18d27b062a6d 100644 --- a/packages/rest/package.json +++ b/packages/rest/package.json @@ -25,6 +25,7 @@ "@loopback/http-server": "^1.2.1", "@loopback/openapi-v3": "^1.3.9", "@loopback/openapi-v3-types": "^1.0.16", + "@loopback/express-middleware": "^1.0.0-1", "@types/body-parser": "^1.17.0", "@types/cors": "^2.8.5", "@types/express": "^4.11.1", diff --git a/packages/rest/src/keys.ts b/packages/rest/src/keys.ts index 2c67bff9b4ee..9e095b73330f 100644 --- a/packages/rest/src/keys.ts +++ b/packages/rest/src/keys.ts @@ -3,16 +3,19 @@ // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT -import {CoreBindings} from '@loopback/core'; import {BindingKey, Context} from '@loopback/context'; - +import {CoreBindings} from '@loopback/core'; +import {HttpProtocol} from '@loopback/http-server'; +import * as https from 'https'; /** * See https://github.com/Microsoft/TypeScript/issues/26985 */ // import {OpenApiSpec} from '@loopback/openapi-v3-types'; import {OpenAPIObject as OpenApiSpec} from 'openapi3-ts'; - +import {ErrorWriterOptions} from 'strong-error-handler'; +import {BodyParser, RequestBodyParser} from './body-parsers'; import {HttpHandler} from './http-handler'; +import {RestRouter, RestRouterOptions} from './router'; import {SequenceHandler} from './sequence'; import { BindElement, @@ -20,20 +23,14 @@ import { GetFromContext, InvokeMethod, LogError, - Request, - Response, ParseParams, Reject, - Send, + Request, RequestBodyParserOptions, + Response, + Send, } from './types'; -import {HttpProtocol} from '@loopback/http-server'; -import * as https from 'https'; -import {ErrorWriterOptions} from 'strong-error-handler'; -import {RestRouter, RestRouterOptions} from './router'; -import {RequestBodyParser, BodyParser} from './body-parsers'; - /** * RestServer-specific bindings */ diff --git a/packages/rest/src/rest.server.ts b/packages/rest/src/rest.server.ts index 02169a041af3..8e384a45f762 100644 --- a/packages/rest/src/rest.server.ts +++ b/packages/rest/src/rest.server.ts @@ -12,6 +12,10 @@ import { inject, } from '@loopback/context'; import {Application, CoreBindings, Server} from '@loopback/core'; +import { + ExpressBindings, + MiddlewareRegistry, +} from '@loopback/express-middleware'; import {HttpServer, HttpServerOptions} from '@loopback/http-server'; import {getControllerSpec} from '@loopback/openapi-v3'; import { @@ -221,24 +225,50 @@ export class RestServer extends Context implements Server, HttpServerLike { this._applyExpressSettings(); this._requestHandler = this._expressApp; + if (!this.isBound(ExpressBindings.EXPRESS_MIDDLEWARE_REGISTRY)) { + // Set up the default express middleware registry + this.bind(ExpressBindings.EXPRESS_MIDDLEWARE_REGISTRY).toClass( + MiddlewareRegistry, + ); + } + const middlewareRegistry = this.getSync( + ExpressBindings.EXPRESS_MIDDLEWARE_REGISTRY, + ); + middlewareRegistry.setMiddlewareRegistryOptions({ + phasesByOrder: ['cors', 'openapi-spec', 'rest'], + }); + // Allow CORS support for all endpoints so that users // can test with online SwaggerUI instance - this._expressApp.use(cors(this.config.cors)); + middlewareRegistry.middleware(cors(this.config.cors), { + phase: 'cors', + name: 'cors', + }); // Set up endpoints for OpenAPI spec/ui - this._setupOpenApiSpecEndpoints(); + this._setupOpenApiSpecEndpoints(middlewareRegistry); // Mount our router & request handler - this._expressApp.use(this._basePath, (req, res, next) => { - this._handleHttpRequest(req, res).catch(next); - }); + middlewareRegistry.middleware( + (req, res, next) => { + this._handleHttpRequest(req, res).catch(next); + }, + { + path: this._basePath, + phase: 'rest', + name: 'rest', + }, + ); // Mount our error handler - this._expressApp.use( + middlewareRegistry.errorMiddleware( (err: Error, req: Request, res: Response, next: Function) => { this._onUnhandledError(req, res, err); }, + {name: 'error'}, ); + + this._expressApp.use(middlewareRegistry.requestHandler); } /** @@ -258,7 +288,7 @@ export class RestServer extends Context implements Server, HttpServerLike { * Mount /openapi.json, /openapi.yaml for specs and /swagger-ui, /explorer * to redirect to externally hosted API explorer */ - protected _setupOpenApiSpecEndpoints() { + protected _setupOpenApiSpecEndpoints(middlewareRegistry: MiddlewareRegistry) { if (this.config.openApiSpec.disabled) return; // NOTE(bajtos) Regular routes are handled through Sequence. // IMO, this built-in endpoint should not run through a Sequence, @@ -270,14 +300,24 @@ export class RestServer extends Context implements Server, HttpServerLike { const mapping = this.config.openApiSpec.endpointMapping!; // Serving OpenAPI spec for (const p in mapping) { - this._expressApp.get(p, (req, res) => - this._serveOpenApiSpec(req, res, mapping[p]), + middlewareRegistry.middleware( + (req, res) => this._serveOpenApiSpec(req, res, mapping[p]), + { + path: p, + method: 'get', + phase: 'openapi-spec', + }, ); } const explorerPaths = ['/swagger-ui', '/explorer']; - this._expressApp.get(explorerPaths, (req, res, next) => - this._redirectToSwaggerUI(req, res, next), + middlewareRegistry.middleware( + (req, res, next) => this._redirectToSwaggerUI(req, res, next), + { + path: explorerPaths, + method: 'get', + phase: 'openapi-spec', + }, ); }