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.
@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.
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.
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.
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.
logic was copied from https://github.com/restrry/kibana/blob/master/src/core/public/http/http_setup.ts#L50-L56
|
@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.
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.
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.
with handler RFC we might want to unify them, but atm it works as you described.
There was a problem hiding this comment.
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.
in this case we have to create BastPath instance for every Request. don't we?
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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.
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:
modifyUrlhelpers.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.basePathoption, which affects all routes when Kibana is run behind a proxy. To simplify URL manipulations to include/excludeserver.basePathpart, New platform collocates underbasePathnamespace a set of helpers as a part of CoreSetup.http contract: