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

[Core] Explicit typings for request handler context #88718

Merged
merged 50 commits into from Jan 21, 2021

Conversation

mshustov
Copy link
Contributor

@mshustov mshustov commented Jan 19, 2021

Summary

Part of #57588
This PR removes interface augmentation pattern for RequestHandlerContext type.
If a plugin extends RequestHandlerContext with a custom property or accesses a property defined by a dependency, it should declare a context type explicitly.

Before:

declare module 'src/core/server' {
  interface RequestHandlerContext {
    myPlugin?: MyPluginApi;
  }
}

const router = http.createRouter();
http.registerRouteHandlerContext('my-plugin', async (context, req, res) => {...});

After:

export interface MyPluginRequestHandlerContext extends RequestHandlerContext {
  myPlugin: MyPluginApi;
}
const router = http.createRouter<MyPluginRequestHandlerContext>();
http.registerRouteHandlerContext<MyPluginRequestHandlerContext, 'my-plugin'>(
  'my-plugin',
  async (context, req, res) => {...}
);

The benefits of the approach:

  • avoids global type pollution
  • it's easier to grasp the request handler context interface
  • request handler context interface can be adjusted to reflect plugin required & optional dependencies

Plugin API Changes

Whenever Kibana needs to get access to data saved in elasticsearch, it should perform a check whether an end-user has access to the data.
On the server-side, API requiring impersonation with an incoming request, are exposed via context argument of request handler:

const router = core.http.createRouter();
router.get(
  { path: '/api/my-plugin/', validate:  },
  async (context, req, res) => {}
)

Starting from the current version your plugin should declare an interface of this context parameter explicitly.
Before:

declare module 'src/core/server' {
  interface RequestHandlerContext {
    myPlugin?: MyPluginApi;
  }
}

const router = http.createRouter();
http.registerRouteHandlerContext('my-plugin', async (context, req, res) => {...});

After:

export interface MyPluginRequestHandlerContext extends RequestHandlerContext {
  myPlugin: MyPluginApi;
}
const router = http.createRouter<MyPluginRequestHandlerContext>();
http.registerRouteHandlerContext<MyPluginRequestHandlerContext, 'my-plugin'>(
  'my-plugin',
  async (context, req, res) => {...}
);

Copy link
Contributor

@justinkambic justinkambic left a comment

Choose a reason for hiding this comment

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

Changes to Uptime app LGTM.

Copy link
Contributor

@chrisronline chrisronline left a comment

Choose a reason for hiding this comment

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

LGTM for stack monitoring

Copy link
Contributor

@streamich streamich left a comment

Choose a reason for hiding this comment

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

AppServices changes LGTM.

Copy link
Contributor

@rylnd rylnd left a comment

Choose a reason for hiding this comment

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

Lists and Detections changes LGTM! I'd like to get (and have requested) approval from someone(s) more familiar with the Cases and Endpoint code, though.

Copy link
Contributor

@XavierM XavierM left a comment

Choose a reason for hiding this comment

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

LGTM for Case and timeline

Copy link
Member

@cnasikas cnasikas left a comment

Choose a reason for hiding this comment

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

LGTM for Case and Timeline

case: CaseRequestContext;
actions: ActionsApiRequestHandlerContext;
// TODO: Remove when triggers_ui do not import case's types.
// PR https://github.com/elastic/kibana/pull/84587.
Copy link
Member

@cnasikas cnasikas Jan 20, 2021

Choose a reason for hiding this comment

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

Super nit -> The comments should be removed right? To my understanding it is required to declare all plugin dependencies context and we should not remove the securitySolution, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@paul-tavares paul-tavares left a comment

Choose a reason for hiding this comment

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

LGTM from a Security Solution Endpoint Management standpoint

@wylieconlon wylieconlon added v8.0.0 and removed 8.0.0 labels Jan 20, 2021
Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

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

ES UI changes look good to me!

x-pack/plugins/cross_cluster_replication/server/types.ts Outdated Show resolved Hide resolved
Copy link
Member

@afharo afharo left a comment

Choose a reason for hiding this comment

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

Code LGTM! I think we'll need a follow-up to fix the @ts-expect-error bits. But I think we can move on for now to unblock the TS refs efforts.

{
provider: IContextProvider<THandler, keyof HandlerContextType<THandler>>;
provider: IContextProvider<any, any>;
Copy link
Member

Choose a reason for hiding this comment

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

Super-NIT: I think this generalization of the types makes TS lose the references to THandler. And that is causing the arity problems down the line. IMO, we can revisit these types later to unblock the TS References migrations.

Copy link
Contributor

@pgayvallet pgayvallet left a comment

Choose a reason for hiding this comment

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

LGTM. That was something!

@@ -11,6 +11,7 @@ import { first, map } from 'rxjs/operators';
import { Server } from '@hapi/hapi';
import { pick } from '@kbn/std';

import type { RequestHandlerContext } from 'src/core/server';
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: can we use relative import here?

Copy link
Contributor Author

@mshustov mshustov Jan 21, 2021

Choose a reason for hiding this comment

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

we can, but RequestHandlerContext declared in 'src/core/server/index.ts'. I'd prefer we move it to http in a separate PR not sure what is the best place to keep it, RequestHandlerContext is Kibana application-specific type, not related to http service

@@ -341,10 +349,11 @@ export type RequestHandler<
P = unknown,
Q = unknown,
B = unknown,
Context extends RequestHandlerContext = RequestHandlerContext,
Copy link
Contributor

Choose a reason for hiding this comment

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

Some plugins are declaring their handlers outside of the route registration, so the handler's generics are not inferred

e.g

const handler = ...
router.get(config, handler);

body: mockOptInStatus,
body: '["mock_opt_in_hashed_value"]',
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: why the change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fetch body doesn't accept string[], but string. after the fix, the test reflects the change.

@@ -35,7 +35,7 @@ export async function sendTelemetryOptInStatus(

await fetch(optInStatusUrl, {
method: 'post',
body: optInStatus,
body: JSON.stringify(optInStatus),
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably because of the removed ts-ignore?

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
core 447 446 -1

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
core 563.8KB 558.4KB -5.4KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@mshustov mshustov requested a review from smith January 21, 2021 13:54
@mshustov mshustov merged commit b3a9754 into elastic:master Jan 21, 2021
kibana-core [DEPRECATED] automation moved this from Pending Review to Done (7.12) Jan 21, 2021
@mshustov mshustov deleted the explicit-request-hanlder-context branch January 21, 2021 14:20
mshustov added a commit that referenced this pull request Jan 21, 2021
* move context to server part. couple with RequestHandlerContext

Context implementation will be simplified in follow-up.

* adopt core code

* adopt bfetch code

* adopt data code

* adopt search examples

* adopt vis_type_timelion

* adopt vis_type_timeseries

* adopt plugin functional tests

* adopt actions

* adopt alerting plugin

* adopt APM plugin

* adopt beats_management

* adopt case plugin

* adopt cross_cluster_replication

* adopt data_enhanced

* adopt event_log

* adopt global_search

* adopt index_management

* adopt infra

* adopt licensing

* adopt lists

* adopt logstash

* adopt reporting

* adopt observability

* adopt monitoring

* adopt rollup

* adopt so tagging

* adopt security

* adopt security_solutions

* adopt watcher

* adopt uptime

* adopt spaces

* adopt snapshot_restore

* adopt features changes

* mute error when null used to extend context

* update docs

* small cleanup

* add type safety for return type

* refactor registerRouteHandlerContext type

* update docs

* update license header

* update docs

* fix type error. fetch body does not accept array of strings

* fix telemetry test

* remove unnecessary ts-ignore

* address comments

* update docs
# Conflicts:
#	docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md
#	src/plugins/data/server/server.api.md
#	x-pack/plugins/monitoring/server/plugin.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backported Feature:ExpressionLanguage Interpreter expression language (aka canvas pipeline) release_note:plugin_api_changes Contains a Plugin API changes section for the breaking plugin API changes section. Team:APM All issues that need APM UI Team support Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v7.12.0 v8.0.0
Projects
Development

Successfully merging this pull request may close these issues.

None yet