-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Openapi and api explorer to honor basePath #2554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -180,6 +180,13 @@ export class RestServer extends Context implements Server, HttpServerLike { | |
| config.host = undefined; | ||
| } | ||
|
|
||
| this.basePath(config.basePath); | ||
|
|
||
| const OPENAPI_SPEC_MAPPING: {[key: string]: OpenApiSpecForm} = { | ||
| [`${this._basePath}/openapi.json`]: {version: '3.0.0', format: 'json'}, | ||
| [`${this._basePath}/openapi.yaml`]: {version: '3.0.0', format: 'yaml'}, | ||
| }; | ||
|
|
||
| config.openApiSpec = config.openApiSpec || {}; | ||
| config.openApiSpec.endpointMapping = | ||
| config.openApiSpec.endpointMapping || OPENAPI_SPEC_MAPPING; | ||
|
|
@@ -206,8 +213,6 @@ export class RestServer extends Context implements Server, HttpServerLike { | |
| this.sequence(config.sequence); | ||
| } | ||
|
|
||
| this.basePath(config.basePath); | ||
|
|
||
| this.bind(RestBindings.BASE_PATH).toDynamicValue(() => this._basePath); | ||
| this.bind(RestBindings.HANDLER).toDynamicValue(() => this.httpHandler); | ||
| } | ||
|
|
@@ -277,7 +282,10 @@ export class RestServer extends Context implements Server, HttpServerLike { | |
| ); | ||
| } | ||
|
|
||
| const explorerPaths = ['/swagger-ui', '/explorer']; | ||
| const explorerPaths = [ | ||
| `${this._basePath}/swagger-ui`, | ||
| `${this._basePath}/explorer`, | ||
| ]; | ||
| this._expressApp.get(explorerPaths, (req, res, next) => | ||
| this._redirectToSwaggerUI(req, res, next), | ||
| ); | ||
|
|
@@ -510,7 +518,9 @@ export class RestServer extends Context implements Server, HttpServerLike { | |
| debug('Redirecting to swagger-ui from %j.', request.originalUrl); | ||
| const protocol = this._getProtocolForRequest(request); | ||
| const baseUrl = protocol === 'http' ? config.httpUrl : config.url; | ||
| const openApiUrl = `${this._getUrlForClient(request)}/openapi.json`; | ||
| const openApiUrl = `${this._getUrlForClient(request)}${ | ||
| this._basePath | ||
| }/openapi.json`; | ||
| const fullUrl = `${baseUrl}?url=${openApiUrl}`; | ||
| response.redirect(308, fullUrl); | ||
| } | ||
|
|
@@ -920,11 +930,6 @@ export interface OpenApiSpecForm { | |
| format?: string; | ||
| } | ||
|
|
||
| const OPENAPI_SPEC_MAPPING: {[key: string]: OpenApiSpecForm} = { | ||
| '/openapi.json': {version: '3.0.0', format: 'json'}, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, we should preserve In your proposal, when app developers specify custom mapping, then their custom endpoints won't be prefixed with In my proposal,
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leaving OPENAPI_SPEC_MAPPING where it is and applying Yes, I propose that custom mapping should be truly custom and not be altered once it is set by a developer. IMO this will give developers more flexibility. But I'm fine either way as long as we have this PR moving forward. My main blocker is inability to customize
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, that's what I'm seeing now. Please note // explorePath is default to `/explorer`
application.static(explorerPath, swaggerUI.getAbsoluteFSPath()); But If we want keep
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I am envisioning this differently. Instead of re-creating a new mapping object, we should apply - this._expressApp.get(p, (req, res) =>
+ this._expressApp.get(basePath + p, (req, res) => |
||
| '/openapi.yaml': {version: '3.0.0', format: 'yaml'}, | ||
| }; | ||
|
|
||
| /** | ||
| * Options to customize how OpenAPI specs are served | ||
| */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am also not sure we want these endpoints to honor
basePathoption.@raymondfeng @strongloop/loopback-maintainers what's your opinion? When the application is configured with a custom
basePath, e.g./api, should we apply the base path to openapi endpoints too?/openapi.jsonand e.g./api/products/api/openapi.jsonand e.g./api/productsI am afraid the proposed implementation is a breaking change requiring a semver-major release. I think we should preserve backwards compatibility and introduce a new feature flag allowing users to decide whether to apply basePath configuration to openapi endpoints or not. By default, we should fall back to old behavior, but new projects scaffolded by
lb4 clishould enable the new behavior.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bajtos Having
/exploreralways running at the root creates problems when there's a reverse proxy running in front of the API. Here's our situation and I'm sure this is pretty common case for many production environments.We have both UI and API applications running on the same host behind
nginx.UI runs at:
http://www.mysite.comLoopback API runs at:
http://www.mysite.com/_apiWhenever a requests come for
/_api/*nginxforwards it to Loopback API. All other requests to to the UI application.As a result requests to http://www.mysite.com/explorer fail because they don't even reach the Loopback app. Hence my fix, which allows explorer to run at http://www.mysite.com/_api/explorer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think
basePathwas introduced for this purpose. There are 3 paths that build a route to a controller method:basePath: it's used as_expressApp.use(basePath, <lb4-rest-router>);, such as/apibasePath(set by @api): it's prepended to the path from step 3, such as/productspath(set by @get, @post etc): local path of the operation, such as/{id}Please note 1 is for express middleware mounting and it is transparent to our REST API routes. Express will strip
/apifromrequest.urlproperty, which becomes/products/{id}.2 + 3 is for internal routing by
@loopback/rest.Putting reverse proxy aside, the http url for a method is:
/<serverBasePath>/<controllerBasePath>/<operationPath>, such as/api/products/{id}and api explorer is exposed at/explorerby default.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raymondfeng Then my question is: is there a way to expose the API explorer at some different route (like
/myprefix/explorer)?I did create a workaround in my project but it's quite hacky and involves messing with the express route stack directly. I'd like to avoid doing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dkrantsberg I'd like to better understand your scenario.
Do you have two servers, one for UI and another for LoopBack API? If that's the case, then I would expect you should be able to configure your nginx instance as follows:
http://www.mysite.com/_api/products/{id}) are forwarded to LB instance and_apiis stripped from the path (e.g./products/{id}).http://www.mysite.com/_api/explorer. Alternatively, I believe it should be possible to configure nginx and define a new virtual route (e.g.http://www.mysite.com/api-explorer) that will be forwarded to/explorerin LB.I think the key is to keep empty
basePathsetting in LoopBack.In case you are running both UI and LB API in the same server, how do you compose these two sets of routes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The self-hosted version of API Explorer that's provided by
@loopback/rest-exploreris already honoringbasePathsetting and allows customization of the Explorer URL, seehttps://github.com/strongloop/loopback-next/tree/master/packages/rest-explorer#basic-use
The redirection to externally-hosted API Explorer, which is built into
@loopback/rest, does not support customization of the URL and it also ignoresbasePathsetting. See here:https://github.com/strongloop/loopback-next/blob/6e0eeb66b6a8c79d736fcc2dc7d9c76bfd57abd3/packages/rest/src/rest.server.ts#L288-L291
Please note that these redirects are deprecated, we want our users to use the self-hosted variant provided by
@loopback/rest.