Open bajtos opened 5 years ago
@bajtos
working on it :)
To support redirects used by REST (redirect to externally hosted swagger-ui) and REST API Explorer (redirect from /explorer
to /explorer/
), we need a way how to build the target location dynamically from the incoming request.
I am re-posting my proposal from https://github.com/strongloop/loopback-next/pull/2314#pullrequestreview-199618046:
I would like to propose a solution that's more generic and can be useful to more consumers.
The built-in redirect needs to obtain the full URL (including protocol, hostname and port) before the redirect URL can be constructed. Inside @loopback/rest-explorer
, we want the path portion of the URL. I feel these two uses cases may be pretty common and it would be great to support them as first-class features.
I am proposing to modify app.redirect
to and introduce a new variant that will accept a function instead of a string as the "target" argument.
// simple redirect for ease of use
app.redirect('/foo', '/bar');
// the built-in redirect
app.redirect('/explorer', ({protocol, host, basePath} => {
const baseUrl = protocol === 'http' ? config.httpUrl : config.url
// host is "hostname:port"
const openApiUrl = `${protocol}://${host}${basePath}/openapi.json`;
const fullUrl = `${baseUrl}?url=${openApiUrl}`;
});
// api-explorer redirect, "urlPath" is the requested path (URL)
app.redirect('/explorer', {urlPath} => urlPath + '/');
// or even simpler - depending on how basePath is applied
app.redirect('/explorer', '/explorer/');
https://github.com/strongloop/loopback-next/pull/2314#issuecomment-461814050 As I am envisioning this functionality, it will be the responsibility of LB4 framework to obtain the host and protocol from the incoming request before calling user-provided function to build the target path/url. This way we can keep the complex logic for obtaining the right host/protocol/etc. inside the framework, individual redirects don't have to repeat this logic and will avoid accidental errors.
(...)
Different applications will have different needs when it comes to target URLs. For example, when running behind a url-rewriting reverse proxy, it's probably easiest to redirect to a path only (e.g. Location: /base-path/target
) and let the reverse proxy figure out the actual URL the client should see.
That's why I proposed that LB4 runtime should provide {protocol, host, basePath, urlPath}
to the handler function and let the handler to decide how exactly it want to construct the redirect target.
This is a follow-up for https://github.com/strongloop/loopback-next/pull/2014.
When using LB4+ to serve HTML pages, it's useful to add a trailing slash to the URL when serving a folder, for example redirect
/explorer
to/explorer/
. Without this redirect, relative URLs to assets like CSS & JS files are incorrectly resolved. For example, when served from/explorer
, relative links like./swagger-ui.css
are resolved in the parent directory, e.g./swagger-ui.css
instead of/explorer/swagger-ui.css
.Right now, a redirect can be implemented using a controller route that's hidden from the documentation and uses HTTP
response
object to send back the redirect. Such solution requires a lot of code and feels a bit hacky.Let's make redirects a first-class feature in LB4 and provide a high-level API that's easy to use.
For example:
Under the hood, this can be implemented as a new Route class, for example:
A mock-up implementation of RedirectRoute:
Acceptance criteria
https://github.com/strongloop/loopback-next/pull/2512
RestServer
.RestApplication
at integration or acceptance level, just to ensure the new RestApplication API is covered.TODO
.redirect(
and consider updating them to use the new route and/or the new RestServer/RestApplication sugar APIs. E.g. REST API Explorer./explorer
to/explorer/
http://example.com
) instead of a local path (/home
). The trick is to skip appendingbasePath
.req.baseUrl
when the LB4 app is mounted on an external Express application.