Skip to content

Commit

Permalink
feat(rest): use @loopback/express-middleware to manage express middle…
Browse files Browse the repository at this point in the history
…ware
  • Loading branch information
raymondfeng committed Mar 6, 2019
1 parent 6cb1d92 commit e9cc630
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 28 deletions.
1 change: 1 addition & 0 deletions packages/rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@loopback/context": "^1.6.0",
"@loopback/core": "^1.1.7",
"@loopback/http-server": "^1.1.7",
"@loopback/express-middleware": "^1.0.0-1",
"@loopback/openapi-v3": "^1.2.3",
"@loopback/openapi-v3-types": "^1.0.7",
"@types/body-parser": "^1.17.0",
Expand Down
29 changes: 17 additions & 12 deletions packages/rest/src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,35 @@
// 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 {ExpressContext} from '@loopback/express-middleware';
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} from './router';
import {SequenceHandler} from './sequence';
import {
BindElement,
FindRoute,
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} from './router';
import {RequestBodyParser, BodyParser} from './body-parsers';

/**
* RestServer-specific bindings
*/
Expand Down Expand Up @@ -80,6 +78,13 @@ export namespace RestBindings {
*/
export const ROUTER = BindingKey.create<RestRouter>('rest.router');

/**
* Binding key for rest express context
*/
export const EXPRESS_CONTEXT = BindingKey.create<ExpressContext>(
'rest.express.context',
);

/**
* Binding key for setting and injecting Reject action's error handling
* options.
Expand Down
60 changes: 44 additions & 16 deletions packages/rest/src/rest.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

import {
Binding,
BindingAddress,
BindingScope,
Constructor,
Context,
inject,
BindingScope,
BindingAddress,
} from '@loopback/context';
import {Application, CoreBindings, Server} from '@loopback/core';
import {ExpressContext} from '@loopback/express-middleware';
import {HttpServer, HttpServerOptions} from '@loopback/http-server';
import {getControllerSpec} from '@loopback/openapi-v3';
import {
Expand All @@ -38,11 +39,11 @@ import {
ControllerInstance,
ControllerRoute,
createControllerFactoryForBinding,
ExternalExpressRoutes,
RedirectRoute,
Route,
RouteEntry,
RoutingTable,
ExternalExpressRoutes,
RedirectRoute,
} from './router';
import {DefaultSequence, SequenceFunction, SequenceHandler} from './sequence';
import {
Expand All @@ -51,9 +52,9 @@ import {
ParseParams,
Reject,
Request,
RequestBodyParserOptions,
Response,
Send,
RequestBodyParserOptions,
} from './types';

const debug = debugFactory('loopback:rest:server');
Expand Down Expand Up @@ -218,6 +219,12 @@ export class RestServer extends Context implements Server, HttpServerLike {
this._applyExpressSettings();
this._requestHandler = this._expressApp;

const expressCtx = new ExpressContext(this);
expressCtx.setMiddlewareRegistryOptions({
phasesByOrder: ['cors', 'openapi-spec', 'rest'],
});
this.bind(RestBindings.EXPRESS_CONTEXT).to(expressCtx);

// Allow CORS support for all endpoints so that users
// can test with online SwaggerUI instance
const corsOptions = this.config.cors || {
Expand All @@ -228,22 +235,33 @@ export class RestServer extends Context implements Server, HttpServerLike {
maxAge: 86400,
credentials: true,
};
this._expressApp.use(cors(corsOptions));

expressCtx.middleware(cors(corsOptions), {phase: 'cors', name: 'cors'});

// Set up endpoints for OpenAPI spec/ui
this._setupOpenApiSpecEndpoints();
this._setupOpenApiSpecEndpoints(expressCtx);

// Mount our router & request handler
this._expressApp.use(this._basePath, (req, res, next) => {
this._handleHttpRequest(req, res).catch(next);
});
expressCtx.middleware(
(req, res, next) => {
this._handleHttpRequest(req, res).catch(next);
},
{
path: this._basePath,
phase: 'rest',
name: 'rest',
},
);

// Mount our error handler
this._expressApp.use(
expressCtx.errorMiddleware(
(err: Error, req: Request, res: Response, next: Function) => {
this._onUnhandledError(req, res, err);
},
{name: 'error'},
);

this._expressApp.use(expressCtx.requestHandler);
}

/**
Expand All @@ -260,7 +278,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(expressCtx: ExpressContext) {
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,
Expand All @@ -272,14 +290,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]),
expressCtx.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),
expressCtx.middleware(
(req, res, next) => this._redirectToSwaggerUI(req, res, next),
{
path: explorerPaths,
method: 'get',
phase: 'openapi-spec',
},
);
}

Expand Down

0 comments on commit e9cc630

Please sign in to comment.