-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Unify base path in HttpService #38237
Unify base path in HttpService #38237
Conversation
Pinging @elastic/kibana-platform |
slashes: boolean | null; | ||
port: string | null; | ||
query: ParsedUrlQuery | {}; | ||
auth?: string | null; |
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.
@azasypkin what do you think if we relay on node typings and get rid of null
?
import { UrlWithParsedQuery } from 'url';
export type URLMeaningfulParts = Pick<
UrlWithParsedQuery,
'auth' | 'hash' | 'hostname' | 'pathname' | 'protocol' | 'slashes' | 'port' | 'query'
>;
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'm fine if Node typings are correct. IIRC last time I checked these didn't reflect completely what was happening in reality, like Node typings were saying that auth/whatever?: string
, but in reality it was auth: null | string
.
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.
Indeed, it works as you described and that's very confusing. Let's keep it as is. I will add a comment to re-consider behavior with newer @types/node
version, because the latest v10.12.30
has the same problems.
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.
We should consider submitting an upstream PR, in my experience it's pretty quick to get fixes merged into the types project.
public prepend = (path: string): string => { | ||
if (!this.basePath) return path; | ||
return modifyUrl(path, parts => { | ||
if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) { |
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.
@joshdover should we attach |
💔 Build Failed |
basePath: { | ||
get: (request: KibanaRequest | Request) => string; | ||
set: (request: KibanaRequest | Request, basePath: string) => void; | ||
prepend: (url: string) => string; |
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.
prepend
on client and server are different a bit. basePath can be request specific on the server side, so probably we can extend api to
prepend: (url: string) => string;
prepend: (request: KibanaRequest | Request, url: string) => string;
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 request-specific basePath is needed because of spaces, correct? The client still needs the space prefix in its basePath, but the user can only be on a single space at a given time, where as the server may be serving multiple spaces at a time. For this reason, the request
needs to be passed to the basePath methods on the server each time we get the basePath, but on the client, the current space is globally configured so this is not needed.
Just trying to make sure I understand.
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.
with handler RFC we might want to unify them, but atm it works as you described.
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.
Another way to make prepend and other helpers request specific would be to make these static functions on the BasePath class:
prepend: (basepath: Basepath, url) => string;
This way these helpers are exactly the same between client and server and there's only one type signature.
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.
in this case we have to create BastPath instance for every Request. don't we?
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.
yeah it gets a bit weird... BasePath
as a data type isn't that useful since it's really just a string, so we could just accept a string instead:
prepend: (basepath: string, url) => string;
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.
that's the thing, end-user doesn't know basepath
value, it is stored in the core by Spaces plugin
basePath: { | ||
get: (request: KibanaRequest | Request) => string; | ||
set: (request: KibanaRequest | Request, basePath: string) => void; | ||
prepend: (url: string) => string; |
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 request-specific basePath is needed because of spaces, correct? The client still needs the space prefix in its basePath, but the user can only be on a single space at a given time, where as the server may be serving multiple spaces at a time. For this reason, the request
needs to be passed to the basePath methods on the server each time we get the basePath, but on the client, the current space is globally configured so this is not needed.
Just trying to make sure I understand.
💚 Build Succeeded |
💔 Build Failed |
retest |
basePath: { | ||
get: (request: KibanaRequest | Request) => string; | ||
set: (request: KibanaRequest | Request, basePath: string) => void; | ||
prepend: (url: string) => string; |
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.
Another way to make prepend and other helpers request specific would be to make these static functions on the BasePath class:
prepend: (basepath: Basepath, url) => string;
This way these helpers are exactly the same between client and server and there's only one type signature.
expect(basePath.prepend('/a/b?x=y#c/d/e')).toBe('/foo/bar/a/b?x=y#c/d/e'); | ||
}); | ||
|
||
it('returns the path unchanged if it does not start with a slash', () => { |
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.
Optional: This is the same as the existing behaviour, but I'm not sure why we implemented this behaviour. It feels like your code can silently fail if you forget a /
in a path you're prepending. The only way you would notice this mistake is by testing it and noticing that the basepath was never added which feels brittle.
Is there a reason we can't handle this case by inserting a /
? If there is a good reason we don't want to accept strings not starting with /
should we perhaps throw an exception to show that this is unexpected/unsupported behaviour instead of pretending like we're giving you a prepended basepath when we are not.
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.
ping @spalger as an author
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 agree that the implicitness is undesirable. I originally did it this way so that the code would ignore fully resolved urls, but I'm not sure if that's being used... sounds like a really tricky thing to figure out.
slashes: boolean | null; | ||
port: string | null; | ||
query: ParsedUrlQuery | {}; | ||
auth?: string | null; |
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.
We should consider submitting an upstream PR, in my experience it's pretty quick to get fixes merged into the types project.
💚 Build Succeeded |
Got the answer from the docs team: only use |
💚 Build Succeeded |
* unify modifyUrl on client and server * create BasePath as a separate entity on server * use BasePath class in http server * use BasePath a separate entity on client * use BasePath class on Http service on the client * switch client code to the new api * improve setver http service mocks * address comments #1 * address comments #2 * update docs * add comment why we define own typings
* unify modifyUrl on client and server * create BasePath as a separate entity on server * use BasePath class in http server * use BasePath a separate entity on client * use BasePath class on Http service on the client * switch client code to the new api * improve setver http service mocks * address comments #1 * address comments #2 * update docs * add comment why we define own typings
Summary
This PR contains breaking changes for NP plugins
Closes #35816
@eliperelman agreed on the proposed interface #36690 (comment)
as he is on vacation I implemented for both client and server.
What's done:
modifyUrl
helpers.https://github.com/restrry/kibana/blob/191ad4caba9f73e6b0648974ff28bad7c806a168/x-pack/plugins/reporting/common/get_absolute_url.ts#L25
Checklist
Use
strikethroughsto remove checklist items you don't feel are applicable to this PR.[ ] This was checked for cross-browser compatibility, including a check against IE11[ ] Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support[ ] This was checked for keyboard-only and screenreader accessibilityFor maintainers
Dev Docs
All requests to Kibana server should be concerned about
server.basePath
option, which affects all routes when Kibana is run behind a proxy. To simplify URL manipulations to include/excludeserver.basePath
part, New platform collocates underbasePath
namespace a set of helpers as a part of CoreSetup.http contract: