diff --git a/packages/rest/package.json b/packages/rest/package.json index 95531a46d2c1..83a0e26ca0da 100644 --- a/packages/rest/package.json +++ b/packages/rest/package.json @@ -25,6 +25,7 @@ "dependencies": { "@loopback/context": "^0.12.5", "@loopback/core": "^0.11.5", + "@loopback/explorer": "^0.1.0", "@loopback/http-server": "^0.3.5", "@loopback/openapi-v3": "^0.12.6", "@loopback/openapi-v3-types": "^0.8.5", diff --git a/packages/rest/src/rest.server.ts b/packages/rest/src/rest.server.ts index 64258e2b30d7..2f058f611e35 100644 --- a/packages/rest/src/rest.server.ts +++ b/packages/rest/src/rest.server.ts @@ -38,6 +38,7 @@ import * as express from 'express'; import {ServeStaticOptions} from 'serve-static'; import {PathParams} from 'express-serve-static-core'; import * as pathToRegExp from 'path-to-regexp'; +import {apiExplorerUI} from '@loopback/explorer'; const debug = require('debug')('loopback:rest:server'); @@ -198,11 +199,25 @@ export class RestServer extends Context implements Server, HttpServerLike { maxAge: 86400, credentials: true, }; + // Set up CORS this._expressApp.use(cors(corsOptions)); // Place the assets router here before controllers this._setupRouterForStaticAssets(); + // Serving OpenAPI spec + for (const p in OPENAPI_SPEC_MAPPING) { + this._expressApp.use(p, (req, res) => + this._serveOpenApiSpec(req, res, OPENAPI_SPEC_MAPPING[p]), + ); + } + + // Serving API Explorer UI + this._expressApp.use('/api-explorer', apiExplorerUI()); + this._expressApp.get('/swagger-ui', (req, res) => + this._redirectToSwaggerUI(req, res, options), + ); + // Mount our router & request handler this._expressApp.use((req, res, next) => { this._handleHttpRequest(req, res, options!).catch(next); @@ -232,28 +247,6 @@ export class RestServer extends Context implements Server, HttpServerLike { response: Response, options: RestServerConfig, ) { - if ( - request.method === 'GET' && - request.url && - request.url in OPENAPI_SPEC_MAPPING - ) { - // NOTE(bajtos) Regular routes are handled through Sequence. - // IMO, this built-in endpoint should not run through a Sequence, - // because it's not part of the application API itself. - // E.g. if the app implements access/audit logs, I don't want - // this endpoint to trigger a log entry. If the server implements - // content-negotiation to support XML clients, I don't want the OpenAPI - // spec to be converted into an XML response. - const settings = OPENAPI_SPEC_MAPPING[request.url]; - return this._serveOpenApiSpec(request, response, settings); - } - if ( - request.method === 'GET' && - request.url && - request.url === '/swagger-ui' - ) { - return this._redirectToSwaggerUI(request, response, options); - } return this.httpHandler.handleRequest(request, response); } @@ -381,11 +374,11 @@ export class RestServer extends Context implements Server, HttpServerLike { 'http'; let host = (request.get('x-forwarded-host') || '').split(',')[0] || - request.headers.host!.replace(/:[0-9]+/, ''); + request.headers.host!.replace(/:([0-9]+)$/, ''); let port = (request.get('x-forwarded-port') || '').split(',')[0] || options.port || - (request.headers.host!.match(/:([0-9]+)/) || [])[1] || + (request.headers.host!.match(/:([0-9]+)$/) || [])[1] || ''; // clear default ports