Skip to content
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

feat: rest explorer now hosts its own copy of oas by default #3133

Merged
merged 1 commit into from
Sep 24, 2019
Merged

feat: rest explorer now hosts its own copy of oas by default #3133

merged 1 commit into from
Sep 24, 2019

Conversation

mgabeler-lee-6rs
Copy link
Contributor

@mgabeler-lee-6rs mgabeler-lee-6rs commented Jun 12, 2019

This PR updates the rest-explorer to, by default, cause the main RestServer to expose an additional copy of the OpenAPI spec at path that is fixed relative to the explorer itself. The explorer then gives the path to the spec as a relative one.

The goal of this is to make the explorer work reliably when behind a reverse proxy that does non-trivial URL transforms (such as placing the app under a path prefix). Since such reverse proxy configurations are generally external to the app, it may be difficult for the app to reliably know the absolute path to itself.

Making it use a relative URL for the OpenAPI spec means that it doesn't need to care at all about path or hostname transformations a proxy might apply.

This behavior is enabled by default, but possible to disable in case some corner case I've not thought of requires the old behavior.

This should fix #2285.
This replaces #2293. See that PR for useful background, discussion, and links to more of the same.

Checklist

  • npm test passes on your machine
  • New tests added or existing tests modified to cover all changes
  • Code conforms with the style guide
  • API Documentation in code was updated
  • Documentation in /docs/site was updated
  • Affected artifact templates in packages/cli were updated
    • N/A AFAIK
  • Affected example projects in examples/* were updated
    • I had to update the version in examples/todo/package.json to make the tests happy, not sure if this was "proper"
  • Verify this with a real reverse proxy configuration equivalent to that which exposed the original issue

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @mgabeler-lee-6rs for the pull request, this is great!

I have mixed feelings about the new public API RestServer.addOpenApiSpecEndpoint. I would prefer to implement the new endpoint as a regular controller route in REST Explorer:

In ExplorerController, add a new endpoint to server the spec:

class ExplorerController {
  // ...

  spec(): {
    const specObj = this.request.getApiSpec(this.requestContext);
    const spec = JSON.stringify(specObj, null, 2);
    response.setHeader('content-type', 'application/json; charset=utf-8');
    response.end(spec, 'utf-8');
    return response;
  }
}

In RestExplorerComponent, conditionally register this new controller route:

  this.registerControllerRoute('get', explorerPath, 'indexRedirect');
  this.registerControllerRoute('get', explorerPath + '/', 'index');

  if (explorerConfig.useOwnOpenApiSpecEndpoint !== false) {
    const endpointPath = explorerPath + '/' + ExplorerController.OPENAPI_RELATIVE_URL;
    this.registerControllerRoute('get', endpointPath, 'spec');
  }

The missing pieces:

  • Modify RestServer.getApiSpec to accept an optional RequestContext parameter. If the parameter is set, then modify servers and basePath as we are doing in _serveOpenApiSpec now.
  • Find a way how to access the RestServer instance from controllers. For example, you can add a new binding key, similar to RestBindings.Http.CONTEXT and CoreBindings.APPLICATION_INSTANCE.

Thoughts?

packages/rest-explorer/src/rest-explorer.types.ts Outdated Show resolved Hide resolved
packages/rest-explorer/src/rest-explorer.types.ts Outdated Show resolved Hide resolved
packages/rest/src/rest.server.ts Show resolved Hide resolved
Copy link
Contributor Author

@mgabeler-lee-6rs mgabeler-lee-6rs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your suggestions sound good. I wasn't thrilled with addOpenApiSpecEndpoint either, your alternative definitely sounds better.

packages/rest/src/rest.server.ts Show resolved Hide resolved
packages/rest-explorer/src/rest-explorer.types.ts Outdated Show resolved Hide resolved
@mgabeler-lee-6rs
Copy link
Contributor Author

I've updated according to the review notes, and also have done some testing with an actual reverse proxy config, which found two things related to finding the proper server URL for the explorer to talk to when behind a path-modifying proxy:

  1. Using setServersFromRequest breaks things
  2. Still need to manually set servers[].url to have the external base path.

I'm working on an update to try to address these by (conditionally) inserting an entry in servers that uses a computed relative path.

@mgabeler-lee-6rs
Copy link
Contributor Author

Unfortunately it seems swagger-ui / OAS only support "relative" server paths in the sense of them being relative to the server, not relative to the spec path. And there is no standard I can find for reverse proxies passing the original request path in some X-Forwarded-* header.

@mgabeler-lee-6rs
Copy link
Contributor Author

One hack that I considered and explicitly rejected: When loading the spec from the explorer, it is (usually) possible to infer the external URL in use from the Referrer header.

I could add logic to infer a servers entry from the Referrer when present, but that seems brittle and I wouldn't go down that path unless you really think it's worth it. It would produce some quite strange behavior, where the spec the explorer gets is not the same as if you manually load the same spec URL the explorer uses. Not to mention the issues of trying to accurately detect if the referrer even is the self-hosted explorer.

@mgabeler-lee-6rs
Copy link
Contributor Author

mgabeler-lee-6rs commented Jun 13, 2019

I gave a whirl at writing the referer thing to see how ugly it is ... here's what I came up with. I'm not at all sure that it correctly handles all the possible cases of base/mount paths however, and it still seems ... brittle.

diff --git a/packages/rest-explorer/src/rest-explorer.controller.ts b/packages/rest-explorer/src/rest-explorer.controller.ts
index 5f6c0b59..b2d1953b 100644
--- a/packages/rest-explorer/src/rest-explorer.controller.ts
+++ b/packages/rest-explorer/src/rest-explorer.controller.ts
@@ -33,6 +33,7 @@ export class ExplorerController {
 
   private openApiSpecUrl: string;
   private useOwnOpenApiSpecEndpoint: boolean;
+  private explorerPath: string;
 
   constructor(
     @inject(RestBindings.CONFIG, {optional: true})
@@ -47,6 +48,10 @@ export class ExplorerController {
   ) {
     this.useOwnOpenApiSpecEndpoint =
       explorerConfig.useOwnOpenApiSpecEndpoint !== false;
+    this.explorerPath = explorerConfig.path || '/explorer';
+    if (!this.explorerPath.endsWith('/')) {
+      this.explorerPath += '/';
+    }
     this.openApiSpecUrl = this.getOpenApiSpecUrl(restConfig);
   }
 
@@ -89,6 +94,13 @@ export class ExplorerController {
 
   spec() {
     const specObj = this.restServer.getApiSpec(this.requestContext);
+    const referer = this.request.headers.referer;
+    if (this.useOwnOpenApiSpecEndpoint && referer && specObj.servers) {
+      // evil: infer the external server url from the referer header, insert it in the servers list
+      if (referer.endsWith(this.explorerPath)) {
+        specObj.servers.unshift({url: referer.slice(0, -this.explorerPath.length + 1)});
+      }
+    }
     const spec = JSON.stringify(specObj, null, 2);
     this.response.setHeader('content-type', 'application/json; charset=utf-8');
     this.response.end(spec, 'utf-8');

@bajtos
Copy link
Member

bajtos commented Jun 14, 2019

Thank you for a thorough investigation, @mgabeler-lee-6rs. I really appreciate the effort you are putting into this work, especially considering all different dead-ends we have encountered so far.

Unfortunately it seems swagger-ui / OAS only support "relative" server paths in the sense of them being relative to the server, not relative to the spec path.

This looks like a bug in swagger-ui to me. Quoting from https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md#server-object, emphasis is mine:

A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served.

Would you mind reporting an issue to swagger-ui and/or swagger-js?

Maybe I am reading the spec incorrectly and the term "host location" is referring only to the scheme+hostname+port part of the URL? Let's find out :)

And there is no standard I can find for reverse proxies passing the original request path in some X-Forwarded-* header.

Hmm.

I could add logic to infer a servers entry from the Referrer when present, but that seems brittle and I wouldn't go down that path unless you really think it's worth it.

I agree it's rather brittle. I guess I can live with it if we don't find any better solution.


It makes me wonder. As the developer setting up the LB app & the reverse proxy, do you know the URL where the OpenAPI spec can be loaded from? What if we added a new configuration option allowing developers to tell the Explorer where to load the spec from?

At the moment, Explorer accepts a single option - the path where to server the front-end:

https://github.com/strongloop/loopback-next/blob/ba3f3894ef7e102b0fcd8b9b7a1f1d221bbbf4a4/packages/rest-explorer/src/rest-explorer.types.ts#L9-L14

What if we added a new option, e.g. specUrl that will the explorer use, instead of trying to infer the spec URL from the request & server config?

As for the second pard (using setServersFromRequest breaks things + still need to manually set servers[].url to have the external base path), is this actually a problem?

My idea is that if the app is running behind a reverse proxy, then the developer should:

  • configure REST API Explorer with the URL where clients can load the spec from
  • provide servers[].url entry with the URL where clients can access the API

Obviously, that won't work well if there are some clients accessing the server through a reverse proxy and other clients that are accessing the server directly. Is this a relevant use case for you?

@mgabeler-lee-6rs
Copy link
Contributor Author

Thank you for a thorough investigation, @mgabeler-lee-6rs. I really appreciate the effort you are putting into this work, especially considering all different dead-ends we have encountered so far.

You're welcome. Enlightened self-interest and all that 😃

Unfortunately it seems swagger-ui / OAS only support "relative" server paths in the sense of them being relative to the server, not relative to the spec path.

This looks like a bug in swagger-ui to me. Quoting from https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md#server-object, emphasis is mine:

A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served.

Interesting, I was reading https://swagger.io/docs/specification/api-host-and-base-path/#relative-urls which explicitly says "The URLs in the servers array can be relative, such as /v2. In this case, the URL is resolved against the server that hosts the given OpenAPI definition". Clearly the spec is the authoritative source of proper behavior.

Would you mind reporting an issue to swagger-ui and/or swagger-js?

Filed swagger-api/swagger-ui#5401

It makes me wonder. As the developer setting up the LB app & the reverse proxy, do you know the URL where the OpenAPI spec can be loaded from? What if we added a new configuration option allowing developers to tell the Explorer where to load the spec from?

That's basically what this PR addresses -- making the explorer handle that for itself by having a copy of the spec available to it at a constant relative path.

At the moment, Explorer accepts a single option - the path where to server the front-end:

https://github.com/strongloop/loopback-next/blob/ba3f3894ef7e102b0fcd8b9b7a1f1d221bbbf4a4/packages/rest-explorer/src/rest-explorer.types.ts#L9-L14

What if we added a new option, e.g. specUrl that will the explorer use, instead of trying to infer the spec URL from the request & server config?

Well, that's the issue "self-hosting the spec" in this PR resolves -- it allows the explorer to always use a fixed URL to get the spec, and not care for that aspect about any base URLs that are involved, whether they are within loopback or from an external proxy.

As for the second part (using setServersFromRequest breaks things + still need to manually set servers[].url to have the external base path), is this actually a problem?

Not really, no. A minor annoyance only.

My idea is that if the app is running behind a reverse proxy, then the developer should:

  • configure REST API Explorer with the URL where clients can load the spec from

The relative url hosting of the spec in this PR will allow that to be handled automagically.

  • provide servers[].url entry with the URL where clients can access the API

Yup 👍

Obviously, that won't work well if there are some clients accessing the server through a reverse proxy and other clients that are accessing the server directly. Is this a relevant use case for you?

Our use case requires supporting both direct & proxied access, but not at the same time -- developers run with direct access, test/integration & production run behind the proxy. We use the common pattern of a NODE_ENV environment variable to tell the app which scenario it's in.

So, for us, having to set servers[].url manually when running in the proxied configuration is acceptable. We already have a shared utility function to do that as part of building the config object for the app at launch, and it does not require monkey patching loopback classes.

Fixing the relative path handling in swagger-ui would allow us to simplify that helper and remove the environment-conditional for it -- it would simply always be ../ for us.


TL;DR: The relative spec hosting in this PR is sufficient to address our use case.


Will take a swing through and work on bringing up the coverage, and also will take a pass at adding a section to the documentation on how to configure this stuff for path-prefixing reverse proxies like we have.

@bajtos
Copy link
Member

bajtos commented Jul 29, 2019

@mgabeler-lee-6rs what's the status of this pull request? Is there anything I can help you with to move this work forward?

@mgabeler-lee-6rs
Copy link
Contributor Author

I've got local work to sort out the test coverage, but the test are currently broken in my merge from master -- working on sorting that out, I'm sure it's something relatively simple.

@mgabeler-lee-6rs
Copy link
Contributor Author

OK, I think I have this in decent shape ... notes/thoughts:

  • The last commit (editing version in examples/todo/package.json was a bit of hand waving to make the tests pass. I'm not sure it was the proper way to get that done?
  • I had to rebase & force-push this in order to make the Travis commitlint check happy due to the limited git history it fetches. That may have messed up some of the older review notes in GitHub
  • Let me know if you'd like me to squash the commit history for this PR to clean it up
  • On the top level TODO item about verifying this with a real nginx reverse-proxy config: I did actually do that with an earlier version of this PR, just not with the latest updates to it, esp. after the rebase. I have all the setup however so it will be quick & easy to repeat tomorrow.

Here's my nginx config snippet I used for that testing:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen       33000;
    server_name  localhost;

    location = /lb4test {
        return 302 /lb4test/;
    }

    location ^~ /lb4test/ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_http_version 1.1;
        chunked_transfer_encoding off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://172.17.0.1:3000/;
        proxy_send_timeout 10s;
        proxy_read_timeout 10s;
    }
}

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the updates. I quickly skimmed through the new diff, I think conceptually your solution looks good! Now I'll need to set aside a larger amount of time to review it in detail.

@raymondfeng could you please review these changes too?

const specObj = this.restServer.getApiSpec(this.requestContext);
const spec = JSON.stringify(specObj, null, 2);
this.response.setHeader('content-type', 'application/json; charset=utf-8');
this.response.end(spec, 'utf-8');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary for this endpoint to deal with JSON serialization to HTTP response? I believe that by default, LoopBack is automatically serializing controller return values as JSON. I think this controller method can be simplified as follows:

spec() {
  return this.restServer.getApiSpec(this.requestContext);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may well be right. This code is copy-pasta from RestServer._serveOpenApiSpec.

Copy link
Contributor Author

@mgabeler-lee-6rs mgabeler-lee-6rs Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing some git history spelunking, it looks like this code comes from back when it was done at the express level, instead of being a controller level (3286bc6).

A quick local test indicates that your simplification does work, so I'll clean up both copies of this code 👍

Edit: oops, the other copy of this code still is an express handler not a controller endpoint, so that copy needs to stay as-is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I notice happens when I do this: the response is no longer explicitly listed (in the HTTP headers) as being in the UTF-8 encoding (no specific encoding is listed).

I suspect this is largely a non-issue, but let me know if you disagree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I notice happens when I do this: the response is no longer explicitly listed (in the HTTP headers) as being in the UTF-8 encoding (no specific encoding is listed).

That's because of the following line:

https://github.com/strongloop/loopback-next/blob/c944654881140119e44fe9e1db85a0f26e59d658/packages/rest/src/writer.ts#L52

I think the missing charset information is fine as far as this pull request is concerned.

It would be nice to eventually fix the line above to include charset/encoding too - would you like to open a new pull request?

Note also that you cannot use a url-relative path for the `servers` entry, as
the Swagger UI does not support that (yet). You may use a _host_-relative path
however.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make it easy to understand, maybe we should build a table to show different cases with corresponding configurations, such as:

Use case Recommended configuration Exposed spec/UI URL
Running as standalone server
Running behind a reverse proxy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 will work on that

I think the scenarios to consider are:

  • Whether the app is exposed directly or not (i.e. does the request the app received have the original request host directly or in a reverse proxy provided header)
  • Whether there is a path-modifying reverse proxy in front of the app
  • Whether you have advanced an (undetermined) advanced use case where you need the explorer to use a custom OpenAPI spec instead of the LB4 generated one

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to add to more well-known cases to the list:

@mgabeler-lee-6rs
Copy link
Contributor Author

Note: The commit-lint check in Travis is angry because it only clones a limited history depth ... which is causing the commitlint to not see the branch point for this PR, and thus it's running commit lint against a giant pile of commits that aren't actually part of this PR. I can rebase this PR (again) if cleaning that up is important.

@raymondfeng
Copy link
Contributor

@mgabeler-lee-6rs We use rebase to pick up upstream changes into the PR. See https://loopback.io/doc/en/lb4/submitting_a_pr.html#6-rebasing

example, in the default configuration, it will expose `/explorer/openapi.json`,
or in the examples above with the Explorer path configured, it would expose
`/openapi/ui/openapi.json`. This is to allow it to use a fixed relative path to
load the spec, to be tolerant of running behind reverse proxies.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it disable the spec endpoints exposed by @loopback/rest if the explorer component has its own?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it leaves those un-touched

<sup>2</sup> Due to limitations in the OpenAPI spec and what information is
provided by the reverse proxy to the app, this is a scenario without a clear
means of getting a working explorer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

packages/rest-explorer/src/rest-explorer.types.ts Outdated Show resolved Hide resolved
@bajtos bajtos mentioned this pull request Aug 26, 2019
4 tasks
* the externally visible path, as that information is not systematically
* forwarded to the application behind the proxy.
*/
relativeOpenApiSpecEndpoint?: false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So valid values of relativeOpenApiSpecEndpoint:

  1. false
  2. undefined

true is not allowed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was the idea here for now. The default is enabled, you can use this flag to explicitly disable it. If this is too obtuse, can make this a simple boolean.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's meant to only allow explicitly set relativeOpenApiSpecEndpoint to false, I'm fine with it.

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good, I'd like to discuss few places before I approve the patch.

Note also that you cannot use a url-relative path for the `servers` entry, as
the Swagger UI does not support that (yet). You may use a _host_-relative path
however.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to add to more well-known cases to the list:

@inject(RestBindings.Http.REQUEST) private request: Request,
@inject(RestBindings.Http.CONTEXT) private requestContext: RequestContext,
@inject(RestBindings.Http.RESPONSE) private response: Response,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need to inject request and response when we are injecting the full requestContext? Those two objects can be accessed as requestContext.request and requestContext.response.

https://github.com/strongloop/loopback-next/blob/6b4808084ce86e67a3a2982db2bc2ea350c6768e/packages/rest/src/request-context.ts#L93-L99

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing

@@ -688,6 +710,24 @@ export class RestServer extends Context implements Server, HttpServerLike {
}

assignRouterSpec(spec, this._externalRoutes.routerSpec);

if (requestContext) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use reverse logic & early return to make the code easier to reason about and keep the level of indentation low.

if (!requestContext) {
  return spec;
}

if (this.config.openApiSpec.setServersFromRequest)
// ...
return spec;

Alternatively, and I think that's a better solution, can you extract this code into a helper function?

if (requestContext) {
  spec = updateSpecFromRequest(spec, requestContext);
}
return spec;

@mgabeler-lee-6rs
Copy link
Contributor Author

Quoting a few since a prior rebase means GitHub won't let me reply to some review comments directly...

This is a known problem of the current implementation, see #433

Fixing

Alternatively, and I think that's a better solution, can you extract this code into a helper function.

Fixing

I'd like to add to more well-known cases to the list

I'm less familiar with these use cases, will read up a bit and update the PR with info in a followup commit soon

@raymondfeng
Copy link
Contributor

@mgabeler-lee-6rs Thank you for the update. But CI is failing - https://travis-ci.com/strongloop/loopback-next/jobs/236909000. Please investigate.

@mgabeler-lee-6rs
Copy link
Contributor Author

Yup, working on it -- the bug I fixed related to having the explorer work in some of the base path related scenarios broke some test expectations, fix will be easy

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @mgabeler-lee-6rs for the updates, the patch is almost good to get merged, at least as far as I am concerned.

I have few minor comments to consider, PTAL.

@@ -1,6 +1,6 @@
{
"name": "@loopback/example-todo",
"version": "1.7.4",
"version": "1.8.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are bumping up version numbers during the release process, please revert this line.

Copy link
Contributor Author

@mgabeler-lee-6rs mgabeler-lee-6rs Sep 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do -- but note that it will cause CI to fail, I think? It causes test to fail locally at any rate

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's weird and not expected at all. Can you try to rebase your PR on top of the latest master please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, oops ... forgot to switch git reflexes to fork mode and thought I was already up to date there... I suspect that will do the trick

const url = this.request.originalUrl || this.request.url;
this.response.redirect(301, url + '/');
let url =
this.requestContext.request.originalUrl ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeating this.requestContext. prefix is tedious, have you considered the following refactoring?

const {request, response} = requestContext;

let url = request.originalUrl || request.url;
// etc.

@@ -28,6 +28,13 @@ export class RestExplorerComponent implements Component {

this.registerControllerRoute('get', explorerPath, 'indexRedirect');
this.registerControllerRoute('get', explorerPath + '/', 'index');
if (restExplorerConfig.relativeOpenApiSpecEndpoint !== false) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have mixed feelings about the option name relativeOpenApiSpecEndpoint, I feel it's describing implementation details instead of the intent. How about useSelfHostedSpec or selfHostSpec?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why I didn't think of this before, useSelfHostedSpec is much clearer & simpler 😀

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👏 💯

Let's get @raymondfeng feedback too.

The last step will be to squash all commits into a single one and write a descriptive commit message - see https://github.com/strongloop/loopback-next/blob/master/docs/site/DEVELOPING.md#commit-message-guidelines

This makes it much easier to use the explorer with more complex
configurations such as base paths, express composition, and path-modifying
reverse proxies.
@mgabeler-lee-6rs
Copy link
Contributor Author

Rebased & squashed

Thanks for the patience & feedback!

@raymondfeng raymondfeng merged commit 887556e into loopbackio:master Sep 24, 2019
@raymondfeng
Copy link
Contributor

@mgabeler-lee-6rs PR landed 🥇 Thank you for the great contribution!

@mgabeler-lee-6rs mgabeler-lee-6rs deleted the feat/rest-explorer-self-host-oas branch September 24, 2019 17:09
@bajtos
Copy link
Member

bajtos commented Sep 26, 2019

Thank you @mgabeler-lee-6rs for your perseverance ❤️ It's great to see this work finished and landed 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

rest-explorer doesn't work behind path-mapping proxy
3 participants