-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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): add redirect route #2314
Conversation
packages/rest/test/unit/rest.server/rest.server.redirect.unit.ts
Outdated
Show resolved
Hide resolved
packages/rest/test/unit/rest.application/rest.application.unit.ts
Outdated
Show resolved
Hide resolved
@bajtos review please |
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.
Thank you @sanadHaj for the pull request.
I love the idea of app.redirect
👍 It will help us to simplify the implementation of @loopback/rest
and get rid of indexRedirect, see
I don't like the idea of SwaggerUIRedirect route. These redirects are preserved for backwards compatibility, we can remove them in the next semver-major version. Adding extra complexity just to support this route seems like too much maintenance overhead.
I would like to propose a different 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/');
Besides the comment above and the comments below, I'd like to discuss the impact of basePath
on redirects. Should we apply basePath to source
, target
or both? I'd like us to find a solution that will be least confusing to our users. Personally, I am leaning towards applying basePath
to both of them. Obviously, when the target
is a full URL like https://explorer.loopback.io/...
, then basePath
must not be applied.
packages/rest/src/rest.server.ts
Outdated
* @param target URL path of the endpoint | ||
*/ | ||
redirect(source: string, target: string): Binding { | ||
return this.route(new RedirectRoute(source, this._basePath + target)); |
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 find this surprising. Why are we prepending this._basePath
to target
, but not to source
? I would expect basePath to be prepended to both or to none. What am I missing?
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 find this surprising. Why are we prepending
this._basePath
totarget
, but not tosource
? I would expect basePath to be prepended to both or to none. What am I missing?
- adding the the base path to the source will cause to double the base path so the result will be
something like basePath/basePath/redirectRoute. - the reason of adding base path to source to avoid 404 not found cause the location header will not hold the base path so when the request come back during the redirect process express/lb4 router will return 404.
eventually i wanna to achieve to redirect
route if not exist this will help developers and give them some flexibility of using redirect api
lets assume i have configured the lb4 app like this ;
restApp.basePath('/api');
await restApp.controller(barController).lock();
await restApp.controller(fooController).lock();
restApp.redirect('/foo','/bar');
restApp.redirect('/notExistRoute','/bar');
await restApp.start();
in the above example the user will not figure out what happening behind the scene , removing the base path to be added as target /api/bar
a litile bit confusing me .
the result of requesting /api/foo
and /api/notExistRoute
it will be the bar controller response.
even when the api/notExistRoute
missing as route .
lets discuss high level first .
how you intend to get the host and protocol , currently we extract them from request .
it should be const openApiUrl = `${protocol}://${host}/openapi.json`; please see the above comment for more information.
|
In #2330, we have moved test files from Sorry for the inconvenience. |
Good discussion!
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.
I think this is not going to work for the redirecting to externally-hosted swagger-ui, where the target is pointing to that external URL and using the location of the LB4 app as a query string parameter. 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. That's why I proposed that LB4 runtime should provide
I am of a different opinion, I think the openapi endpoint should honor To move this work forward, I am proposing to split this pull request into multiple smaller steps:
Thoughts? /cc @strongloop/loopback-maintainers |
I see that you already took the opposite approach and simplified this pull request to implement only string-based redirect route. That's fine with me too, I am going to review the code changes now. |
packages/rest/src/__tests__/acceptance/routing/routing.acceptance.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/acceptance/routing/routing.acceptance.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/acceptance/routing/routing.acceptance.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/acceptance/routing/routing.acceptance.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/acceptance/routing/routing.acceptance.ts
Outdated
Show resolved
Hide resolved
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 patch looks pretty good now!
Besides the comments below, please add test cases to verify the following scenarios:
- A custom status code provided to
app.redirect()
- A custom status code provided to
server.redirect()
- What happens when
basePath
is set - how is the target URL constructed. Must have: server-level test. Nice to have: acceptance-level test against an applicaition. - Priority of a redirect route vs. a static assets route.
packages/rest/src/__tests__/integration/rest.application.integration.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/integration/rest.application.integration.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/integration/rest.server.integration.ts
Outdated
Show resolved
Hide resolved
packages/rest/src/__tests__/unit/rest.application/rest.application.unit.ts
Outdated
Show resolved
Hide resolved
add RedirectRoute class by implementing RouteEntry, ResolvedRoute with adding the method redirect for both rest server and app
add mores tests (unit/integration/acceptance) to cover theRedirectRote using the server and app api (redirect method).
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 have rebased the patch on top of the latest master
, squashed commits into a single one, updated the commit message and also made minor improvements in tests & doc comments.
Let's wait for CI results before landing.
Hmm, I am not able to push into your feature branch :( I'll have to open a new PR to get this landed. |
Closing in favor of #2512. |
Fixes #2022
Implement RedirectRoute to redirect request route , beside SwaggerRoute that extend from RedirectRoute to redirect swagger ui including some refactoring of rest server to support the new swagger route instead of express middleware
The implementation, including 12 (unit/integration/acceptance) tests.
Checklist
npm test
passes on your machinepackages/cli
were updatedexamples/*
were updated