Decouple RequestHandler from CoreRequestHandlerContext (#135448)

* Decouple RequestHandler from CoreRequestHandlerContext

* fix service default type

* split core context providers

* introduce type definition for the sub contexts

* ensure the root implementation implements the root interface

* adapt SO route definitions

* adapt uiSettings route definitions

* fix more internal routes

* adapt SO route integration tests

* adapt SO legacy route integration tests

* fix more types

* am I getting anywhere?

* did it do the trick?

* fix test failure

* export pre-scoped IRouter for external consumers

* fix wrong path import

* fix public export of HttpServiceSetup

* fix more usages

* work around again

* fix RequestHandler usage

* fix more violations

* fix more violations

* let's try another approach

* fix test file

* revert some unecessary changes

* revert some unecessary changes bis

* cleanup external changes

* some tsdoc cleanup

* more cleanup

* try to fix mock types

* export CoreRequestHandlerContext sub-parts

* export base types for renamed public types

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Pierre Gayvallet 2022-07-06 10:51:11 +02:00 committed by GitHub
parent 4d301fdf4d
commit e88c743f1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 774 additions and 330 deletions

View file

@ -10,7 +10,7 @@ import { flatten } from 'lodash';
import { ShallowPromise, MaybePromise } from '@kbn/utility-types';
import type { PluginOpaqueId } from '@kbn/core-base-common';
import type { CoreId } from '@kbn/core-base-common-internal';
import type { RequestHandler, RequestHandlerContext } from '../..';
import type { RequestHandler, RequestHandlerContextBase } from '../..';
/**
* A function that returns a context value for a specific key of given context type.
@ -26,7 +26,7 @@ import type { RequestHandler, RequestHandlerContext } from '../..';
* @public
*/
export type IContextProvider<
Context extends RequestHandlerContext,
Context extends RequestHandlerContextBase,
ContextName extends keyof Context
> = (
// context.core will always be available, but plugin contexts are typed as optional
@ -148,7 +148,7 @@ export interface IContextContainer {
* @param provider - A {@link IContextProvider} to be called each time a new context is created.
* @returns The {@link IContextContainer} for method chaining.
*/
registerContext<Context extends RequestHandlerContext, ContextName extends keyof Context>(
registerContext<Context extends RequestHandlerContextBase, ContextName extends keyof Context>(
pluginOpaqueId: PluginOpaqueId,
contextName: ContextName,
provider: IContextProvider<Context, ContextName>
@ -195,7 +195,7 @@ export class ContextContainer implements IContextContainer {
}
public registerContext = <
Context extends RequestHandlerContext,
Context extends RequestHandlerContextBase,
ContextName extends keyof Context
>(
source: symbol,
@ -243,7 +243,7 @@ export class ContextContainer implements IContextContainer {
const builtContextPromises: Record<string, Promise<unknown>> = {};
const builtContext = {} as HandlerContextType<RequestHandler>;
(builtContext as unknown as RequestHandlerContext).resolve = async (keys) => {
(builtContext as unknown as RequestHandlerContextBase).resolve = async (keys) => {
const resolved = await Promise.all(
keys.map(async (key) => {
return [key, await builtContext[key]];

View file

@ -19,6 +19,7 @@ import { HttpResources, HttpResourcesServiceToolkit } from '../http_resources';
import { InternalCorePreboot, InternalCoreSetup } from '../internal_types';
import { registerBundleRoutes } from './bundle_routes';
import { UiPlugins } from '../plugins';
import type { InternalCoreAppRequestHandlerContext } from './internal_types';
/** @internal */
interface CommonRoutesParams {
@ -85,7 +86,7 @@ export class CoreApp {
private registerDefaultRoutes(coreSetup: InternalCoreSetup, uiPlugins: UiPlugins) {
const httpSetup = coreSetup.http;
const router = httpSetup.createRouter('');
const router = httpSetup.createRouter<InternalCoreAppRequestHandlerContext>('');
const resources = coreSetup.httpResources.createRegistrar(router);
router.get({ path: '/', validate: false }, async (context, req, res) => {

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { RequestHandlerContextBase } from '..';
import type { IRouter } from '../http';
import type { UiSettingsRequestHandlerContext } from '../ui_settings';
/**
* Request handler context used by core's coreApp routes.
* @internal
*/
export interface InternalCoreAppRequestHandlerContext extends RequestHandlerContextBase {
core: Promise<{
uiSettings: UiSettingsRequestHandlerContext;
}>;
}
/**
* Router bound to the {@link InternalCoreAppRequestHandlerContext}.
* Used by core's coreApp routes.
* @internal
*/
export type InternalCoreAppRouter = IRouter<InternalCoreAppRequestHandlerContext>;

View file

@ -6,131 +6,63 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line max-classes-per-file
import { InternalCoreStart } from './internal_types';
import { KibanaRequest } from './http/router';
import { SavedObjectsClientContract } from './saved_objects/types';
import type { InternalCoreStart } from './internal_types';
import type { KibanaRequest } from './http';
import {
InternalSavedObjectsServiceStart,
ISavedObjectTypeRegistry,
SavedObjectsClientProviderOptions,
CoreSavedObjectsRouteHandlerContext,
SavedObjectsRequestHandlerContext,
} from './saved_objects';
import { InternalElasticsearchServiceStart, IScopedClusterClient } from './elasticsearch';
import { InternalUiSettingsServiceStart, IUiSettingsClient } from './ui_settings';
import { DeprecationsClient, InternalDeprecationsServiceStart } from './deprecations';
import {
CoreElasticsearchRouteHandlerContext,
ElasticsearchRequestHandlerContext,
} from './elasticsearch';
import { CoreUiSettingsRouteHandlerContext, UiSettingsRequestHandlerContext } from './ui_settings';
import {
CoreDeprecationsRouteHandlerContext,
DeprecationsRequestHandlerContext,
} from './deprecations';
class CoreElasticsearchRouteHandlerContext {
#client?: IScopedClusterClient;
constructor(
private readonly elasticsearchStart: InternalElasticsearchServiceStart,
private readonly request: KibanaRequest
) {}
public get client() {
if (this.#client == null) {
this.#client = this.elasticsearchStart.client.asScoped(this.request);
}
return this.#client;
}
/**
* The `core` context provided to route handler.
*
* Provides the following clients and services:
* - {@link SavedObjectsClient | savedObjects.client} - Saved Objects client
* which uses the credentials of the incoming request
* - {@link ISavedObjectTypeRegistry | savedObjects.typeRegistry} - Type registry containing
* all the registered types.
* - {@link IScopedClusterClient | elasticsearch.client} - Elasticsearch
* data client which uses the credentials of the incoming request
* - {@link IUiSettingsClient | uiSettings.client} - uiSettings client
* which uses the credentials of the incoming request
* @public
*/
export interface CoreRequestHandlerContext {
savedObjects: SavedObjectsRequestHandlerContext;
elasticsearch: ElasticsearchRequestHandlerContext;
uiSettings: UiSettingsRequestHandlerContext;
deprecations: DeprecationsRequestHandlerContext;
}
class CoreSavedObjectsRouteHandlerContext {
constructor(
private readonly savedObjectsStart: InternalSavedObjectsServiceStart,
private readonly request: KibanaRequest
) {}
#scopedSavedObjectsClient?: SavedObjectsClientContract;
#typeRegistry?: ISavedObjectTypeRegistry;
public get client() {
if (this.#scopedSavedObjectsClient == null) {
this.#scopedSavedObjectsClient = this.savedObjectsStart.getScopedClient(this.request);
}
return this.#scopedSavedObjectsClient;
}
public get typeRegistry() {
if (this.#typeRegistry == null) {
this.#typeRegistry = this.savedObjectsStart.getTypeRegistry();
}
return this.#typeRegistry;
}
public getClient = (options?: SavedObjectsClientProviderOptions) => {
if (!options) return this.client;
return this.savedObjectsStart.getScopedClient(this.request, options);
};
public getExporter = (client: SavedObjectsClientContract) => {
return this.savedObjectsStart.createExporter(client);
};
public getImporter = (client: SavedObjectsClientContract) => {
return this.savedObjectsStart.createImporter(client);
};
}
class CoreUiSettingsRouteHandlerContext {
#client?: IUiSettingsClient;
constructor(
private readonly uiSettingsStart: InternalUiSettingsServiceStart,
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext
) {}
public get client() {
if (this.#client == null) {
this.#client = this.uiSettingsStart.asScopedToClient(
this.savedObjectsRouterHandlerContext.client
);
}
return this.#client;
}
}
class CoreDeprecationsRouteHandlerContext {
#client?: DeprecationsClient;
constructor(
private readonly deprecationsStart: InternalDeprecationsServiceStart,
private readonly elasticsearchRouterHandlerContext: CoreElasticsearchRouteHandlerContext,
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext
) {}
public get client() {
if (this.#client == null) {
this.#client = this.deprecationsStart.asScopedToClient(
this.elasticsearchRouterHandlerContext.client,
this.savedObjectsRouterHandlerContext.client
);
}
return this.#client;
}
}
export class CoreRouteHandlerContext {
/**
* The concrete implementation for Core's route handler context.
*
* @internal
*/
export class CoreRouteHandlerContext implements CoreRequestHandlerContext {
readonly elasticsearch: CoreElasticsearchRouteHandlerContext;
readonly savedObjects: CoreSavedObjectsRouteHandlerContext;
readonly uiSettings: CoreUiSettingsRouteHandlerContext;
readonly deprecations: CoreDeprecationsRouteHandlerContext;
constructor(
private readonly coreStart: InternalCoreStart,
private readonly request: KibanaRequest
) {
this.elasticsearch = new CoreElasticsearchRouteHandlerContext(
this.coreStart.elasticsearch,
this.request
);
this.savedObjects = new CoreSavedObjectsRouteHandlerContext(
this.coreStart.savedObjects,
this.request
);
constructor(coreStart: InternalCoreStart, request: KibanaRequest) {
this.elasticsearch = new CoreElasticsearchRouteHandlerContext(coreStart.elasticsearch, request);
this.savedObjects = new CoreSavedObjectsRouteHandlerContext(coreStart.savedObjects, request);
this.uiSettings = new CoreUiSettingsRouteHandlerContext(
this.coreStart.uiSettings,
coreStart.uiSettings,
this.savedObjects
);
this.deprecations = new CoreDeprecationsRouteHandlerContext(
this.coreStart.deprecations,
coreStart.deprecations,
this.elasticsearch,
this.savedObjects
);

View file

@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreElasticsearchRouteHandlerContext } from '../elasticsearch';
import type { CoreSavedObjectsRouteHandlerContext } from '../saved_objects';
import type { DeprecationsClient, InternalDeprecationsServiceStart } from './deprecations_service';
/**
* Core's `deprecations` request handler context.
* @public
*/
export interface DeprecationsRequestHandlerContext {
client: DeprecationsClient;
}
/**
* The {@link DeprecationsRequestHandlerContext} implementation.
* @internal
*/
export class CoreDeprecationsRouteHandlerContext implements DeprecationsRequestHandlerContext {
#client?: DeprecationsClient;
constructor(
private readonly deprecationsStart: InternalDeprecationsServiceStart,
private readonly elasticsearchRouterHandlerContext: CoreElasticsearchRouteHandlerContext,
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext
) {}
public get client() {
if (this.#client == null) {
this.#client = this.deprecationsStart.asScopedToClient(
this.elasticsearchRouterHandlerContext.client,
this.savedObjectsRouterHandlerContext.client
);
}
return this.#client;
}
}

View file

@ -25,3 +25,5 @@ export type {
export { DeprecationsService } from './deprecations_service';
export { config } from './deprecation_config';
export { CoreDeprecationsRouteHandlerContext } from './deprecations_route_handler_context';
export type { DeprecationsRequestHandlerContext } from './deprecations_route_handler_context';

View file

@ -0,0 +1,26 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { IRouter } from '../http';
import type { RequestHandlerContextBase } from '..';
import type { DeprecationsRequestHandlerContext } from './deprecations_route_handler_context';
/**
* Request handler context used by core's deprecations routes.
* @internal
*/
export interface InternalDeprecationRequestHandlerContext extends RequestHandlerContextBase {
core: Promise<{ deprecations: DeprecationsRequestHandlerContext }>;
}
/**
* Router bound to the {@link InternalDeprecationRequestHandlerContext}.
* Used by core's deprecations routes.
* @internal
*/
export type InternalDeprecationRouter = IRouter<InternalDeprecationRequestHandlerContext>;

View file

@ -5,10 +5,11 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { IRouter } from '../../http';
import { DeprecationsGetResponse } from '../types';
export const registerGetRoute = (router: IRouter) => {
import type { DeprecationsGetResponse } from '../types';
import type { InternalDeprecationRouter } from '../internal_types';
export const registerGetRoute = (router: InternalDeprecationRouter) => {
router.get(
{
path: '/',

View file

@ -7,9 +7,10 @@
*/
import { InternalHttpServiceSetup } from '../../http';
import type { InternalDeprecationRequestHandlerContext } from '../internal_types';
import { registerGetRoute } from './get';
export function registerRoutes({ http }: { http: InternalHttpServiceSetup }) {
const router = http.createRouter('/api/deprecations');
const router = http.createRouter<InternalDeprecationRequestHandlerContext>('/api/deprecations');
registerGetRoute(router);
}

View file

@ -0,0 +1,39 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { KibanaRequest } from '../http';
import type { IScopedClusterClient } from './client';
import type { InternalElasticsearchServiceStart } from './types';
/**
* Core's `elasticsearch` request handler context.
* @public
*/
export interface ElasticsearchRequestHandlerContext {
client: IScopedClusterClient;
}
/**
* The {@link UiSettingsRequestHandlerContext} implementation.
* @internal
*/
export class CoreElasticsearchRouteHandlerContext implements ElasticsearchRequestHandlerContext {
#client?: IScopedClusterClient;
constructor(
private readonly elasticsearchStart: InternalElasticsearchServiceStart,
private readonly request: KibanaRequest
) {}
public get client() {
if (this.#client == null) {
this.#client = this.elasticsearchStart.client.asScoped(this.request);
}
return this.#client;
}
}

View file

@ -54,3 +54,5 @@ export {
isNotFoundFromUnsupportedServer,
PRODUCT_RESPONSE_HEADER,
} from './supported_server_response_check';
export { CoreElasticsearchRouteHandlerContext } from './elasticsearch_route_handler_context';
export type { ElasticsearchRequestHandlerContext } from './elasticsearch_route_handler_context';

View file

@ -8,6 +8,7 @@
import { ExecutionContextContainer } from '@kbn/core-execution-context-browser-internal';
import * as kbnTestServer from '../../../test_helpers/kbn_server';
import { RequestHandlerContext } from '../..';
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
@ -63,7 +64,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping({}, { meta: true });
@ -86,7 +87,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -109,7 +110,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping({}, { meta: true });
@ -128,7 +129,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -147,7 +148,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping(
@ -194,7 +195,7 @@ describe('trace', () => {
const { http } = await rootExecutionContextDisabled.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -217,7 +218,7 @@ describe('trace', () => {
const { http, executionContext } = await rootExecutionContextDisabled.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set(parentContext);
const esClient = (await context.core).elasticsearch.client;
@ -250,7 +251,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set(parentContext);
return res.ok({ body: executionContext.get() });
@ -265,7 +266,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set(parentContext);
await delay(100);
@ -281,7 +282,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
let id = 42;
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set({ ...parentContext, id: String(id++) });
@ -301,7 +302,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
let id = 2;
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set({ ...parentContext, id: String(id) });
@ -329,7 +330,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
let id = 2;
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set(parentContext);
@ -364,7 +365,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, (context, req, res) =>
res.ok({ body: executionContext.get() })
);
@ -382,7 +383,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -416,7 +417,7 @@ describe('trace', () => {
registerOnPreResponse,
} = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
return res.ok({ body: executionContext.get()?.toJSON() });
});
@ -470,7 +471,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -492,7 +493,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping({}, { meta: true });
@ -514,7 +515,7 @@ describe('trace', () => {
const { http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -537,7 +538,7 @@ describe('trace', () => {
const { http, executionContext } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
executionContext.set(parentContext);
const esClient = (await context.core).elasticsearch.client;
@ -561,7 +562,7 @@ describe('trace', () => {
const { http, executionContext } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
const ctx = {
type: 'test-type',
name: 'test-name',
@ -588,7 +589,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
return executionContext.withContext(parentContext, () =>
res.ok({ body: executionContext.get() })
@ -604,7 +605,7 @@ describe('trace', () => {
const { executionContext, http } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
const nestedContext = {
type: 'nested-type',
name: 'nested-name',
@ -630,7 +631,7 @@ describe('trace', () => {
const { http, executionContext } = await root.setup();
const { createRouter } = http;
const router = createRouter('');
const router = createRouter<RequestHandlerContext>('');
const newContext = {
type: 'new-type',
name: 'new-name',

View file

@ -25,7 +25,7 @@ import {
} from './router';
import { HttpServer } from './http_server';
import { Readable } from 'stream';
import { RequestHandlerContext } from '..';
import { RequestHandlerContextBase } from '..';
import { KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils';
import moment from 'moment';
import { of } from 'rxjs';
@ -466,7 +466,7 @@ test('not inline handler - KibanaRequest', async () => {
const router = new Router('/foo', logger, enhanceWithContext);
const handler = (
context: RequestHandlerContext,
context: RequestHandlerContextBase,
req: KibanaRequest<unknown, unknown, { bar: string; baz: number }>,
res: KibanaResponseFactory
) => {

View file

@ -30,6 +30,7 @@ import { OnPreAuthToolkit } from './lifecycle/on_pre_auth';
import { OnPreResponseToolkit } from './lifecycle/on_pre_response';
import { ExternalUrlConfig } from './external_url';
import type { IAuthHeadersStorage } from './auth_headers_storage';
import type { RequestHandlerContextBase } from '..';
type BasePathMocked = jest.Mocked<InternalHttpServiceSetup['basePath']>;
type AuthMocked = jest.Mocked<InternalHttpServiceSetup['auth']>;
@ -38,9 +39,9 @@ export type HttpServicePrebootMock = jest.Mocked<HttpServicePreboot>;
export type InternalHttpServicePrebootMock = jest.Mocked<
Omit<InternalHttpServicePreboot, 'basePath'>
> & { basePath: BasePathMocked };
export type HttpServiceSetupMock = jest.Mocked<
Omit<HttpServiceSetup, 'basePath' | 'createRouter'>
> & {
export type HttpServiceSetupMock<
ContextType extends RequestHandlerContextBase = RequestHandlerContextBase
> = jest.Mocked<Omit<HttpServiceSetup<ContextType>, 'basePath' | 'createRouter'>> & {
basePath: BasePathMocked;
createRouter: jest.MockedFunction<() => RouterMock>;
};
@ -166,10 +167,12 @@ const createInternalSetupContractMock = () => {
return mock;
};
const createSetupContractMock = () => {
const createSetupContractMock = <
ContextType extends RequestHandlerContextBase = RequestHandlerContextBase
>() => {
const internalMock = createInternalSetupContractMock();
const mock: HttpServiceSetupMock = {
const mock: HttpServiceSetupMock<ContextType> = {
createCookieSessionStorageFactory: internalMock.createCookieSessionStorageFactory,
registerOnPreRouting: internalMock.registerOnPreRouting,
registerOnPreAuth: jest.fn(),

View file

@ -16,11 +16,11 @@ import type { CoreContext, CoreService } from '@kbn/core-base-server-internal';
import type { PluginOpaqueId } from '@kbn/core-base-common';
import type { InternalExecutionContextSetup } from '@kbn/core-execution-context-server-internal';
import type { RequestHandlerContext } from '..';
import type { RequestHandlerContextBase } from '..';
import { InternalContextSetup, InternalContextPreboot } from '../context';
import { CspConfigType, cspConfig } from './csp';
import { Router } from './router';
import { Router, IRouter } from './router';
import { HttpConfig, HttpConfigType, config as httpConfig } from './http_config';
import { HttpServer } from './http_server';
import { HttpsRedirectServer } from './https_redirect_server';
@ -114,8 +114,13 @@ export class HttpService
server: prebootSetup.server,
registerRouteHandlerContext: (pluginOpaqueId, contextName, provider) =>
prebootServerRequestHandlerContext.registerContext(pluginOpaqueId, contextName, provider),
registerRoutes: (path, registerCallback) => {
const router = new Router(
registerRoutes: <
DefaultRequestHandlerType extends RequestHandlerContextBase = RequestHandlerContextBase
>(
path: string,
registerCallback: (router: IRouter<DefaultRequestHandlerType>) => void
) => {
const router = new Router<DefaultRequestHandlerType>(
path,
this.log,
prebootServerRequestHandlerContext.createHandler.bind(null, this.coreContext.coreId)
@ -157,7 +162,7 @@ export class HttpService
externalUrl: new ExternalUrlConfig(config.externalUrl),
createRouter: <Context extends RequestHandlerContext = RequestHandlerContext>(
createRouter: <Context extends RequestHandlerContextBase = RequestHandlerContextBase>(
path: string,
pluginId: PluginOpaqueId = this.coreContext.coreId
) => {
@ -168,7 +173,7 @@ export class HttpService
},
registerRouteHandlerContext: <
Context extends RequestHandlerContext,
Context extends RequestHandlerContextBase,
ContextName extends keyof Context
>(
pluginOpaqueId: PluginOpaqueId,

View file

@ -9,7 +9,8 @@
import Boom from '@hapi/boom';
import { KibanaResponse, KibanaResponseFactory, kibanaResponseFactory } from './response';
import { wrapErrors } from './error_wrapper';
import { KibanaRequest, RequestHandler, RequestHandlerContext } from '../..';
import { RequestHandlerContextBase } from '../..';
import { KibanaRequest, RequestHandler } from '..';
const createHandler =
(handler: () => any): RequestHandler<any, any, any> =>
@ -18,7 +19,7 @@ const createHandler =
};
describe('wrapErrors', () => {
let context: RequestHandlerContext;
let context: RequestHandlerContextBase;
let request: KibanaRequest<any, any, any>;
let response: KibanaResponseFactory;

View file

@ -24,7 +24,7 @@ import {
} from './response';
import { RouteConfig, RouteConfigOptions, RouteMethod, validBodyOutput } from './route';
import { HapiResponseAdapter } from './response_adapter';
import { RequestHandlerContext } from '../..';
import { RequestHandlerContextBase } from '../..';
import { wrapErrors } from './error_wrapper';
import { RouteValidator } from './validator';
@ -46,7 +46,7 @@ export interface RouterRoute {
*/
export type RouteRegistrar<
Method extends RouteMethod,
Context extends RequestHandlerContext = RequestHandlerContext
Context extends RequestHandlerContextBase = RequestHandlerContextBase
> = <P, Q, B>(
route: RouteConfig<P, Q, B, Method>,
handler: RequestHandler<P, Q, B, Context, Method>
@ -58,7 +58,7 @@ export type RouteRegistrar<
*
* @public
*/
export interface IRouter<Context extends RequestHandlerContext = RequestHandlerContext> {
export interface IRouter<Context extends RequestHandlerContextBase = RequestHandlerContextBase> {
/**
* Resulted path
*/
@ -118,7 +118,7 @@ export type ContextEnhancer<
Q,
B,
Method extends RouteMethod,
Context extends RequestHandlerContext
Context extends RequestHandlerContextBase
> = (handler: RequestHandler<P, Q, B, Context, Method>) => RequestHandlerEnhanced<P, Q, B, Method>;
function getRouteFullPath(routerPath: string, routePath: string) {
@ -202,7 +202,7 @@ function validOptions(
/**
* @internal
*/
export class Router<Context extends RequestHandlerContext = RequestHandlerContext>
export class Router<Context extends RequestHandlerContextBase = RequestHandlerContextBase>
implements IRouter<Context>
{
public routes: Array<Readonly<RouterRoute>> = [];
@ -307,7 +307,7 @@ type WithoutHeadArgument<T> = T extends (first: any, ...rest: infer Params) => i
: never;
type RequestHandlerEnhanced<P, Q, B, Method extends RouteMethod> = WithoutHeadArgument<
RequestHandler<P, Q, B, RequestHandlerContext, Method>
RequestHandler<P, Q, B, RequestHandlerContextBase, Method>
>;
/**
@ -350,7 +350,7 @@ export type RequestHandler<
P = unknown,
Q = unknown,
B = unknown,
Context extends RequestHandlerContext = RequestHandlerContext,
Context extends RequestHandlerContextBase = RequestHandlerContextBase,
Method extends RouteMethod = any,
ResponseFactory extends KibanaResponseFactory = KibanaResponseFactory
> = (
@ -376,7 +376,7 @@ export type RequestHandlerWrapper = <
P,
Q,
B,
Context extends RequestHandlerContext = RequestHandlerContext,
Context extends RequestHandlerContextBase = RequestHandlerContextBase,
Method extends RouteMethod = any,
ResponseFactory extends KibanaResponseFactory = KibanaResponseFactory
>(

View file

@ -21,7 +21,7 @@ import { OnPostAuthHandler } from './lifecycle/on_post_auth';
import { OnPreResponseHandler } from './lifecycle/on_pre_response';
import { IBasePath } from './base_path_service';
import { ExternalUrlConfig } from './external_url';
import type { PluginOpaqueId, RequestHandlerContext } from '..';
import type { PluginOpaqueId, RequestHandlerContextBase } from '..';
/**
* An object that handles registration of http request context providers.
@ -36,7 +36,7 @@ export type RequestHandlerContextContainer = IContextContainer;
* @public
*/
export type RequestHandlerContextProvider<
Context extends RequestHandlerContext,
Context extends RequestHandlerContextBase,
ContextName extends keyof Context
> = IContextProvider<Context, ContextName>;
@ -117,7 +117,9 @@ export interface HttpAuth {
* ```
* @public
*/
export interface HttpServicePreboot {
export interface HttpServicePreboot<
DefaultRequestHandlerType extends RequestHandlerContextBase = RequestHandlerContextBase
> {
/**
* Provides ability to acquire `preboot` {@link IRouter} instance for a particular top-level path and register handler
* functions for any number of nested routes.
@ -135,7 +137,10 @@ export interface HttpServicePreboot {
* ```
* @public
*/
registerRoutes(path: string, callback: (router: IRouter) => void): void;
registerRoutes<ContextType extends DefaultRequestHandlerType = DefaultRequestHandlerType>(
path: string,
callback: (router: IRouter<ContextType>) => void
): void;
/**
* Access or manipulate the Kibana base path
@ -162,7 +167,12 @@ export interface InternalHttpServicePreboot
| 'server'
| 'getServerInfo'
> {
registerRoutes(path: string, callback: (router: IRouter) => void): void;
registerRoutes<
DefaultRequestHandlerType extends RequestHandlerContextBase = RequestHandlerContextBase
>(
path: string,
callback: (router: IRouter<DefaultRequestHandlerType>) => void
): void;
}
/**
@ -237,7 +247,9 @@ export interface InternalHttpServicePreboot
* ```
* @public
*/
export interface HttpServiceSetup {
export interface HttpServiceSetup<
DefaultRequestHandlerType extends RequestHandlerContextBase = RequestHandlerContextBase
> {
/**
* Creates cookie based session storage factory {@link SessionStorageFactory}
* @param cookieOptions {@link SessionStorageCookieOptions} - options to configure created cookie session storage.
@ -333,7 +345,7 @@ export interface HttpServiceSetup {
* @public
*/
createRouter: <
Context extends RequestHandlerContext = RequestHandlerContext
Context extends DefaultRequestHandlerType = DefaultRequestHandlerType
>() => IRouter<Context>;
/**
@ -365,7 +377,7 @@ export interface HttpServiceSetup {
* @public
*/
registerRouteHandlerContext: <
Context extends RequestHandlerContext,
Context extends DefaultRequestHandlerType,
ContextName extends keyof Omit<Context, 'resolve'>
>(
contextName: ContextName,
@ -384,7 +396,7 @@ export interface InternalHttpServiceSetup
auth: HttpServerSetup['auth'];
server: HttpServerSetup['server'];
externalUrl: ExternalUrlConfig;
createRouter: <Context extends RequestHandlerContext = RequestHandlerContext>(
createRouter: <Context extends RequestHandlerContextBase = RequestHandlerContextBase>(
path: string,
plugin?: PluginOpaqueId
) => IRouter<Context>;
@ -392,7 +404,7 @@ export interface InternalHttpServiceSetup
registerStaticDir: (path: string, dirPath: string) => void;
authRequestHeaders: IAuthHeadersStorage;
registerRouteHandlerContext: <
Context extends RequestHandlerContext,
Context extends RequestHandlerContextBase,
ContextName extends keyof Omit<Context, 'resolve'>
>(
pluginOpaqueId: PluginOpaqueId,

View file

@ -8,7 +8,7 @@
import { getApmConfigMock } from './http_resources_service.test.mocks';
import { IRouter, RouteConfig } from '../http';
import { RouteConfig } from '../http';
import { mockCoreContext } from '@kbn/core-base-server-mocks';
import { coreMock } from '../mocks';
@ -25,7 +25,7 @@ describe('HttpResources service', () => {
let service: HttpResourcesService;
let prebootDeps: PrebootDeps;
let setupDeps: SetupDeps;
let router: jest.Mocked<IRouter>;
let router: ReturnType<typeof httpServiceMock.createRouter>;
const kibanaRequest = httpServerMock.createKibanaRequest();
const context = coreMock.createCustomRequestHandlerContext({});
const apmConfig = { mockApmConfig: true };

View file

@ -63,7 +63,10 @@ export class HttpResourcesService implements CoreService<InternalHttpResourcesSe
stop() {}
private createRegistrar(deps: SetupDeps | PrebootDeps, router: IRouter): HttpResources {
private createRegistrar(
deps: SetupDeps | PrebootDeps,
router: IRouter<RequestHandlerContext>
): HttpResources {
return {
register: <P, Q, B, Context extends RequestHandlerContext = RequestHandlerContext>(
route: RouteConfig<P, Q, B, 'get'>,

View file

@ -46,29 +46,26 @@ import {
ElasticsearchServiceSetup,
configSchema as elasticsearchConfigSchema,
ElasticsearchServiceStart,
IScopedClusterClient,
ElasticsearchServicePreboot,
} from './elasticsearch';
import { HttpServicePreboot, HttpServiceSetup, HttpServiceStart } from './http';
import type {
HttpServicePreboot,
HttpServiceSetup,
HttpServiceStart,
IRouter,
RequestHandler,
} from './http';
import { HttpResources } from './http_resources';
import { PluginsServiceSetup, PluginsServiceStart, PluginOpaqueId } from './plugins';
import { IUiSettingsClient, UiSettingsServiceSetup, UiSettingsServiceStart } from './ui_settings';
import { SavedObjectsClientContract } from './saved_objects/types';
import {
ISavedObjectTypeRegistry,
SavedObjectsServiceSetup,
SavedObjectsServiceStart,
ISavedObjectsExporter,
ISavedObjectsImporter,
SavedObjectsClientProviderOptions,
} from './saved_objects';
import { UiSettingsServiceSetup, UiSettingsServiceStart } from './ui_settings';
import { SavedObjectsServiceSetup, SavedObjectsServiceStart } from './saved_objects';
import { CapabilitiesSetup, CapabilitiesStart } from './capabilities';
import { MetricsServiceSetup, MetricsServiceStart } from './metrics';
import { StatusServiceSetup } from './status';
import { CoreUsageDataStart, CoreUsageDataSetup } from './core_usage_data';
import { I18nServiceSetup } from './i18n';
import { DeprecationsServiceSetup, DeprecationsClient } from './deprecations';
import { DeprecationsServiceSetup } from './deprecations';
// Because of #79265 we need to explicitly import, then export these types for
// scripts/telemetry_check.js to work as expected
import {
@ -80,6 +77,9 @@ import {
CoreServicesUsageData,
} from './core_usage_data';
import { PrebootServicePreboot } from './preboot';
import type { CoreRequestHandlerContext } from './core_route_handler_context';
import type { PrebootCoreRequestHandlerContext } from './preboot_core_route_handler_context';
import { KibanaResponseFactory, RouteMethod } from './http';
export type { PrebootServicePreboot } from './preboot';
@ -151,6 +151,7 @@ export type {
UnauthorizedErrorHandlerResult,
UnauthorizedErrorHandlerToolkit,
UnauthorizedErrorHandler,
ElasticsearchRequestHandlerContext,
} from './elasticsearch';
export type {
@ -176,7 +177,6 @@ export type {
HttpResponsePayload,
HttpServerInfo,
HttpServicePreboot,
HttpServiceSetup,
HttpServiceStart,
ErrorHttpResponseOptions,
IKibanaSocket,
@ -199,7 +199,6 @@ export type {
OnPreResponseExtensions,
OnPreResponseInfo,
RedirectResponseOptions,
RequestHandler,
RequestHandlerWrapper,
RequestHandlerContextContainer,
RequestHandlerContextProvider,
@ -208,7 +207,6 @@ export type {
ResponseHeaders,
KibanaResponseFactory,
RouteConfig,
IRouter,
RouteRegistrar,
RouteMethod,
RouteConfigOptions,
@ -387,6 +385,7 @@ export type {
SavedObjectsImportWarning,
SavedObjectsValidationMap,
SavedObjectsValidationSpec,
SavedObjectsRequestHandlerContext,
} from './saved_objects';
export type {
@ -398,6 +397,7 @@ export type {
UiSettingsServiceStart,
UserProvidedValues,
DeprecationSettings,
UiSettingsRequestHandlerContext,
} from './ui_settings';
export type {
@ -421,6 +421,7 @@ export type {
GetDeprecationsContext,
DeprecationsServiceSetup,
DeprecationsClient,
DeprecationsRequestHandlerContext,
} from './deprecations';
export type { AppCategory } from '../types';
@ -473,7 +474,12 @@ export type {
AnalyticsServiceStart,
} from '@kbn/core-analytics-server';
/** @public **/
export type { CoreRequestHandlerContext } from './core_route_handler_context';
/**
* Base, abstract type for request handler contexts.
* @public
**/
export interface RequestHandlerContextBase {
/**
* Await all the specified context parts and return them.
@ -491,7 +497,7 @@ export interface RequestHandlerContextBase {
}
/**
* Base context passed to a route handler.
* Base context passed to a route handler, containing the `core` context part.
*
* @public
*/
@ -499,44 +505,22 @@ export interface RequestHandlerContext extends RequestHandlerContextBase {
core: Promise<CoreRequestHandlerContext>;
}
/** @public */
/**
* @internal
*/
export interface PrebootRequestHandlerContext extends RequestHandlerContextBase {
core: Promise<PrebootCoreRequestHandlerContext>;
}
/**
* Mixin allowing plugins to define their own request handler contexts.
*
* @public
*/
export type CustomRequestHandlerContext<T> = RequestHandlerContext & {
[Key in keyof T]: T[Key] extends Promise<unknown> ? T[Key] : Promise<T[Key]>;
};
/**
* The `core` context provided to route handler.
*
* Provides the following clients and services:
* - {@link SavedObjectsClient | savedObjects.client} - Saved Objects client
* which uses the credentials of the incoming request
* - {@link ISavedObjectTypeRegistry | savedObjects.typeRegistry} - Type registry containing
* all the registered types.
* - {@link IScopedClusterClient | elasticsearch.client} - Elasticsearch
* data client which uses the credentials of the incoming request
* - {@link IUiSettingsClient | uiSettings.client} - uiSettings client
* which uses the credentials of the incoming request
* @public
*/
export interface CoreRequestHandlerContext {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;
getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;
};
elasticsearch: {
client: IScopedClusterClient;
};
uiSettings: {
client: IUiSettingsClient;
};
deprecations: {
client: DeprecationsClient;
};
}
/**
* Context passed to the `setup` method of `preboot` plugins.
* @public
@ -547,7 +531,7 @@ export interface CorePreboot {
/** {@link ElasticsearchServicePreboot} */
elasticsearch: ElasticsearchServicePreboot;
/** {@link HttpServicePreboot} */
http: HttpServicePreboot;
http: HttpServicePreboot<RequestHandlerContext>;
/** {@link PrebootServicePreboot} */
preboot: PrebootServicePreboot;
}
@ -573,7 +557,7 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
/** {@link ExecutionContextSetup} */
executionContext: ExecutionContextSetup;
/** {@link HttpServiceSetup} */
http: HttpServiceSetup & {
http: HttpServiceSetup<RequestHandlerContext> & {
/** {@link HttpResources} */
resources: HttpResources;
};
@ -662,3 +646,42 @@ export const config = {
appenders: appendersSchema as Type<AppenderConfigType>,
},
};
/**
* Public version of RequestHandler, default-scoped to {@link RequestHandlerContext}
* See [@link RequestHandler}
* @public
*/
type PublicRequestHandler<
P = unknown,
Q = unknown,
B = unknown,
Context extends RequestHandlerContext = RequestHandlerContext,
Method extends RouteMethod = any,
ResponseFactory extends KibanaResponseFactory = KibanaResponseFactory
> = RequestHandler<P, Q, B, Context, Method, ResponseFactory>;
export type { PublicRequestHandler as RequestHandler, RequestHandler as BaseRequestHandler };
/**
* Public version of IRouter, default-scoped to {@link RequestHandlerContext}
* See [@link IRouter}
* @public
*/
type PublicRouter<ContextType extends RequestHandlerContext = RequestHandlerContext> =
IRouter<ContextType>;
export type { PublicRouter as IRouter, IRouter as IBaseRouter };
/**
* Public version of RequestHandlerContext, default-scoped to {@link RequestHandlerContext}
* See [@link RequestHandlerContext}
* @public
*/
type PublicHttpServiceSetup<ContextType extends RequestHandlerContext = RequestHandlerContext> =
HttpServiceSetup<ContextType>;
export type {
PublicHttpServiceSetup as HttpServiceSetup,
HttpServiceSetup as BaseHttpServiceSetup,
};

View file

@ -23,6 +23,7 @@ import type {
CoreStart,
StartServicesAccessor,
CorePreboot,
RequestHandlerContext,
} from '.';
import { elasticsearchServiceMock } from './elasticsearch/elasticsearch_service.mock';
import { httpServiceMock } from './http/http_service.mock';
@ -139,7 +140,7 @@ function createCorePrebootMock() {
const mock: CorePrebootMockType = {
analytics: analyticsServiceMock.createAnalyticsServicePreboot(),
elasticsearch: elasticsearchServiceMock.createPreboot(),
http: httpServiceMock.createPrebootContract(),
http: httpServiceMock.createPrebootContract() as CorePrebootMockType['http'],
preboot: prebootServiceMock.createPrebootContract(),
};
@ -159,7 +160,7 @@ function createCoreSetupMock({
pluginStartContract?: any;
} = {}) {
const httpMock: jest.Mocked<CoreSetup['http']> = {
...httpServiceMock.createSetupContract(),
...httpServiceMock.createSetupContract<RequestHandlerContext>(),
resources: httpResourcesMock.createRegistrar(),
};

View file

@ -10,12 +10,34 @@
import { InternalCorePreboot } from './internal_types';
import { IUiSettingsClient } from './ui_settings';
class PrebootCoreUiSettingsRouteHandlerContext {
/**
* @public
*/
export interface PrebootUiSettingsRequestHandlerContext {
client: IUiSettingsClient;
}
/**
* Implementation of {@link PrebootUiSettingsRequestHandlerContext}
* @internal
*/
class PrebootCoreUiSettingsRouteHandlerContext implements PrebootUiSettingsRequestHandlerContext {
constructor(public readonly client: IUiSettingsClient) {}
}
export class PrebootCoreRouteHandlerContext {
readonly uiSettings: PrebootCoreUiSettingsRouteHandlerContext;
/**
* @public
*/
export interface PrebootCoreRequestHandlerContext {
uiSettings: PrebootUiSettingsRequestHandlerContext;
}
/**
* Implementation of {@link PrebootCoreRequestHandlerContext}.
* @internal
*/
export class PrebootCoreRouteHandlerContext implements PrebootCoreRequestHandlerContext {
readonly uiSettings: PrebootUiSettingsRequestHandlerContext;
constructor(private readonly corePreboot: InternalCorePreboot) {
this.uiSettings = new PrebootCoreUiSettingsRouteHandlerContext(

View file

@ -6,14 +6,14 @@
* Side Public License, v 1.
*/
import { IRouter } from '../../http';
import type { InternalRenderingRouter } from '../internal_types';
import type { BootstrapRenderer } from './bootstrap_renderer';
export const registerBootstrapRoute = ({
router,
renderer,
}: {
router: IRouter;
router: InternalRenderingRouter;
renderer: BootstrapRenderer;
}) => {
router.get(

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { RequestHandlerContextBase } from '..';
import type { IRouter } from '../http';
import type { UiSettingsRequestHandlerContext } from '../ui_settings';
/**
* Request handler context used by core's rendering routes.
* @internal
*/
export interface InternalRenderingRequestHandlerContext extends RequestHandlerContextBase {
core: Promise<{
uiSettings: UiSettingsRequestHandlerContext;
}>;
}
/**
* Router bound to the {@link InternalRenderingRequestHandlerContext}.
* Used by core's rendering routes.
* @internal
*/
export type InternalRenderingRouter = IRouter<InternalRenderingRequestHandlerContext>;

View file

@ -29,6 +29,7 @@ import { getSettingValue, getStylesheetPaths } from './render_utils';
import type { HttpAuth, KibanaRequest } from '../http';
import { IUiSettingsClient } from '../ui_settings';
import { filterUiPlugins } from './filter_ui_plugins';
import type { InternalRenderingRequestHandlerContext } from './internal_types';
type RenderOptions =
| (RenderingPrebootDeps & { status?: never; elasticsearch?: never })
@ -42,7 +43,7 @@ export class RenderingService {
http,
uiPlugins,
}: RenderingPrebootDeps): Promise<InternalRenderingServicePreboot> {
http.registerRoutes('', (router) => {
http.registerRoutes<InternalRenderingRequestHandlerContext>('', (router) => {
registerBootstrapRoute({
router,
renderer: bootstrapRendererFactory({
@ -66,7 +67,7 @@ export class RenderingService {
uiPlugins,
}: RenderingSetupDeps): Promise<InternalRenderingServiceSetup> {
registerBootstrapRoute({
router: http.createRouter(''),
router: http.createRouter<InternalRenderingRequestHandlerContext>(''),
renderer: bootstrapRendererFactory({
uiPlugins,
serverBasePath: http.basePath.serverBasePath,

View file

@ -99,3 +99,5 @@ export type { SavedObjectsValidationMap, SavedObjectsValidationSpec } from './va
export { savedObjectsConfig, savedObjectsMigrationConfig } from './saved_objects_config';
export { SavedObjectTypeRegistry } from './saved_objects_type_registry';
export type { ISavedObjectTypeRegistry } from './saved_objects_type_registry';
export { CoreSavedObjectsRouteHandlerContext } from './saved_objects_route_handler_context';
export type { SavedObjectsRequestHandlerContext } from './saved_objects_route_handler_context';

View file

@ -0,0 +1,30 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { RequestHandlerContextBase } from '..';
import type { IRouter } from '../http';
import type { ElasticsearchRequestHandlerContext } from '../elasticsearch';
import type { SavedObjectsRequestHandlerContext } from './saved_objects_route_handler_context';
/**
* Request handler context used by core's savedObjects routes.
* @internal
*/
export interface InternalSavedObjectsRequestHandlerContext extends RequestHandlerContextBase {
core: Promise<{
savedObjects: SavedObjectsRequestHandlerContext;
elasticsearch: ElasticsearchRequestHandlerContext;
}>;
}
/**
* Router bound to the {@link InternalSavedObjectsRequestHandlerContext}.
* Used by core's savedObjects routes.
* @internal
*/
export type InternalSavedObjectRouter = IRouter<InternalSavedObjectsRequestHandlerContext>;

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerBulkCreateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerBulkCreateRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.post(
{
path: '/_bulk_create',

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerBulkGetRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerBulkGetRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.post(
{
path: '/_bulk_get',

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerBulkResolveRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerBulkResolveRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.post(
{
path: '/_bulk_resolve',

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerBulkUpdateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerBulkUpdateRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.put(
{
path: '/_bulk_update',

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerCreateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerCreateRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.post(
{
path: '/{type}/{id?}',

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerDeleteRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerDeleteRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.delete(
{
path: '/{type}/{id}',

View file

@ -6,8 +6,8 @@
* Side Public License, v 1.
*/
import { IRouter } from '../../../http';
import { catchAndReturnBoomErrors } from '../utils';
import type { InternalSavedObjectRouter } from '../../internal_types';
import { deleteUnknownTypeObjects } from '../../deprecations';
interface RouteDependencies {
@ -16,7 +16,7 @@ interface RouteDependencies {
}
export const registerDeleteUnknownTypesRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
{ kibanaIndex, kibanaVersion }: RouteDependencies
) => {
router.post(

View file

@ -10,7 +10,7 @@ import { schema } from '@kbn/config-schema';
import stringify from 'json-stable-stringify';
import { createPromiseFromStreams, createMapStream, createConcatStream } from '@kbn/utils';
import { IRouter, KibanaRequest } from '../../http';
import { KibanaRequest } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import { SavedObjectConfig } from '../saved_objects_config';
import {
@ -18,6 +18,7 @@ import {
SavedObjectsExportByObjectOptions,
SavedObjectsExportError,
} from '../export';
import type { InternalSavedObjectRouter } from '../internal_types';
import { validateTypes, validateObjects, catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
@ -129,7 +130,7 @@ const validateOptions = (
};
export const registerExportRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
{ config, coreUsageData }: RouteDependencies
) => {
const { maxImportExportSize } = config;

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerFindRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerFindRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
const referenceSchema = schema.object({
type: schema.string(),
id: schema.string(),

View file

@ -7,15 +7,18 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerGetRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerGetRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.get(
{
path: '/{type}/{id}',

View file

@ -9,10 +9,10 @@
import { Readable } from 'stream';
import { extname } from 'path';
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import { SavedObjectConfig } from '../saved_objects_config';
import { SavedObjectsImportError } from '../import';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors, createSavedObjectsStreamFromNdJson } from './utils';
interface RouteDependencies {
@ -27,7 +27,7 @@ interface FileStream extends Readable {
}
export const registerImportRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
{ config, coreUsageData }: RouteDependencies
) => {
const { maxImportPayloadBytes } = config;

View file

@ -11,6 +11,7 @@ import { InternalHttpServiceSetup } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import { SavedObjectConfig } from '../saved_objects_config';
import { IKibanaMigrator } from '../migrations';
import type { InternalSavedObjectsRequestHandlerContext } from '../internal_types';
import { registerGetRoute } from './get';
import { registerResolveRoute } from './resolve';
import { registerCreateRoute } from './create';
@ -46,7 +47,8 @@ export function registerRoutes({
kibanaVersion: string;
kibanaIndex: string;
}) {
const router = http.createRouter('/api/saved_objects/');
const router =
http.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
registerGetRoute(router, { coreUsageData });
registerResolveRoute(router, { coreUsageData });
@ -62,7 +64,7 @@ export function registerRoutes({
registerImportRoute(router, { config, coreUsageData });
registerResolveImportErrorsRoute(router, { config, coreUsageData });
const legacyRouter = http.createRouter('');
const legacyRouter = http.createRouter<InternalSavedObjectsRequestHandlerContext>('');
registerLegacyImportRoute(legacyRouter, {
maxImportPayloadBytes: config.maxImportPayloadBytes,
coreUsageData,
@ -70,7 +72,9 @@ export function registerRoutes({
});
registerLegacyExportRoute(legacyRouter, { kibanaVersion, coreUsageData, logger });
const internalRouter = http.createRouter('/internal/saved_objects/');
const internalRouter = http.createRouter<InternalSavedObjectsRequestHandlerContext>(
'/internal/saved_objects/'
);
registerMigrateRoute(internalRouter, migratorPromise);
registerDeleteUnknownTypesRoute(internalRouter, { kibanaIndex, kibanaVersion });

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -28,7 +29,8 @@ describe('POST /api/saved_objects/_bulk_create', () => {
savedObjectsClient = handlerContext.savedObjects.client;
savedObjectsClient.bulkCreate.mockResolvedValue({ saved_objects: [] });
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsBulkCreate.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -30,7 +31,8 @@ describe('POST /api/saved_objects/_bulk_get', () => {
savedObjectsClient.bulkGet.mockResolvedValue({
saved_objects: [],
});
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsBulkGet.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -30,7 +31,8 @@ describe('POST /api/saved_objects/_bulk_resolve', () => {
savedObjectsClient.bulkResolve.mockResolvedValue({
resolved_objects: [],
});
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsBulkResolve.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -27,7 +28,8 @@ describe('PUT /api/saved_objects/_bulk_update', () => {
({ server, httpSetup, handlerContext } = await setupServer());
savedObjectsClient = handlerContext.savedObjects.client;
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsBulkUpdate.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -37,7 +38,8 @@ describe('POST /api/saved_objects/{type}', () => {
savedObjectsClient = handlerContext.savedObjects.client;
savedObjectsClient.create.mockImplementation(() => Promise.resolve(clientResponse));
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsCreate.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -28,7 +29,8 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
savedObjectsClient = handlerContext.savedObjects.getClient();
handlerContext.savedObjects.getClient = jest.fn().mockImplementation(() => savedObjectsClient);
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsDelete.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -12,6 +12,7 @@ import { elasticsearchServiceMock } from '../../../elasticsearch/elasticsearch_s
import { typeRegistryMock } from '../../saved_objects_type_registry.mock';
import { setupServer } from '../test_utils';
import { SavedObjectsType } from '../../..';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -37,7 +38,9 @@ describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () =
handlerContext.elasticsearch.client.asCurrentUser = elasticsearchClient.asCurrentUser;
handlerContext.elasticsearch.client.asInternalUser = elasticsearchClient.asInternalUser;
const router = httpSetup.createRouter('/internal/saved_objects/');
const router = httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>(
'/internal/saved_objects/'
);
registerDeleteUnknownTypesRoute(router, {
kibanaVersion,
kibanaIndex,

View file

@ -19,6 +19,7 @@ import { savedObjectsExporterMock } from '../../export/saved_objects_exporter.mo
import { SavedObjectConfig } from '../../saved_objects_config';
import { registerExportRoute } from '../export';
import { setupServer, createExportableType } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
const allowedTypes = ['index-pattern', 'search'];
@ -41,7 +42,8 @@ describe('POST /api/saved_objects/_export', () => {
);
exporter = handlerContext.savedObjects.getExporter();
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
handlerContext.savedObjects.getExporter = jest
.fn()
.mockImplementation(() => exporter as ReturnType<typeof savedObjectsExporterMock.create>);

View file

@ -15,6 +15,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -38,7 +39,8 @@ describe('GET /api/saved_objects/_find', () => {
savedObjectsClient.find.mockResolvedValue(clientResponse);
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsFind.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -17,6 +17,7 @@ import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_da
import { HttpService, InternalHttpServiceSetup } from '../../../http';
import { createHttpServer, createCoreContext } from '../../../http/test_utils';
import { contextServiceMock, coreMock } from '../../../mocks';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
const coreId = Symbol('core');
@ -41,11 +42,16 @@ describe('GET /api/saved_objects/{type}/{id}', () => {
handlerContext = coreMock.createRequestHandlerContext();
savedObjectsClient = handlerContext.savedObjects.client;
httpSetup.registerRouteHandlerContext(coreId, 'core', async (ctx, req, res) => {
return handlerContext;
});
httpSetup.registerRouteHandlerContext<InternalSavedObjectsRequestHandlerContext, 'core'>(
coreId,
'core',
(ctx, req, res) => {
return handlerContext;
}
);
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsGet.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -17,6 +17,7 @@ import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_da
import { SavedObjectConfig } from '../../saved_objects_config';
import { setupServer, createExportableType } from '../test_utils';
import { SavedObjectsErrorHelpers, SavedObjectsImporter } from '../..';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -69,7 +70,9 @@ describe(`POST ${URL}`, () => {
.fn()
.mockImplementation(() => importer as jest.Mocked<SavedObjectsImporter>);
const router = httpSetup.createRouter('/internal/saved_objects/');
const router = httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>(
'/internal/saved_objects/'
);
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsImport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -17,6 +17,7 @@ import { executionContextServiceMock } from '@kbn/core-execution-context-server-
import { HttpService, InternalHttpServiceSetup } from '../../../http';
import { createHttpServer, createCoreContext } from '../../../http/test_utils';
import { contextServiceMock, coreMock } from '../../../mocks';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
const coreId = Symbol('core');
@ -41,11 +42,16 @@ describe('GET /api/saved_objects/resolve/{type}/{id}', () => {
handlerContext = coreMock.createRequestHandlerContext();
savedObjectsClient = handlerContext.savedObjects.client;
httpSetup.registerRouteHandlerContext(coreId, 'core', async (ctx, req, res) => {
return handlerContext;
});
httpSetup.registerRouteHandlerContext<InternalSavedObjectsRequestHandlerContext, 'core'>(
coreId,
'core',
(ctx, req, res) => {
return handlerContext;
}
);
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsResolve.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -17,6 +17,7 @@ import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_da
import { setupServer, createExportableType } from '../test_utils';
import { SavedObjectConfig } from '../../saved_objects_config';
import { SavedObjectsImporter } from '../..';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -76,7 +77,8 @@ describe(`POST ${URL}`, () => {
.fn()
.mockImplementation(() => importer as jest.Mocked<SavedObjectsImporter>);
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsResolveImportErrors.mockRejectedValue(
new Error('Oh no!') // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail

View file

@ -13,6 +13,7 @@ import { CoreUsageStatsClient } from '../../../core_usage_data';
import { coreUsageStatsClientMock } from '../../../core_usage_data/core_usage_stats_client.mock';
import { coreUsageDataServiceMock } from '../../../core_usage_data/core_usage_data_service.mock';
import { setupServer } from '../test_utils';
import type { InternalSavedObjectsRequestHandlerContext } from '../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
@ -38,7 +39,8 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => {
savedObjectsClient = handlerContext.savedObjects.client;
savedObjectsClient.update.mockResolvedValue(clientResponse);
const router = httpSetup.createRouter('/api/saved_objects/');
const router =
httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsUpdate.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);

View file

@ -8,12 +8,13 @@
import moment from 'moment';
import { schema } from '@kbn/config-schema';
import type { Logger } from '@kbn/logging';
import { InternalCoreUsageDataSetup } from '../../../core_usage_data';
import { IRouter, Logger } from '../../..';
import type { InternalSavedObjectRouter } from '../../internal_types';
import { exportDashboards } from './lib';
export const registerLegacyExportRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
{
kibanaVersion,
coreUsageData,

View file

@ -7,12 +7,14 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter, Logger, SavedObject } from '../../..';
import type { Logger } from '@kbn/logging';
import type { SavedObject } from '../../..';
import { InternalCoreUsageDataSetup } from '../../../core_usage_data';
import type { InternalSavedObjectRouter } from '../../internal_types';
import { importDashboards } from './lib';
export const registerLegacyImportRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
{
maxImportPayloadBytes,
coreUsageData,

View file

@ -38,6 +38,7 @@ import { coreUsageDataServiceMock } from '../../../../core_usage_data/core_usage
import { registerLegacyExportRoute } from '../export';
import { setupServer } from '../../test_utils';
import { loggerMock } from '@kbn/logging-mocks';
import type { InternalSavedObjectsRequestHandlerContext } from '../../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
let coreUsageStatsClient: jest.Mocked<CoreUsageStatsClient>;
@ -49,7 +50,7 @@ describe('POST /api/dashboards/export', () => {
beforeEach(async () => {
({ server, httpSetup } = await setupServer());
const router = httpSetup.createRouter('');
const router = httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementLegacyDashboardsExport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail

View file

@ -38,6 +38,7 @@ import { coreUsageDataServiceMock } from '../../../../core_usage_data/core_usage
import { registerLegacyImportRoute } from '../import';
import { setupServer } from '../../test_utils';
import { loggerMock } from '@kbn/logging-mocks';
import type { InternalSavedObjectsRequestHandlerContext } from '../../../internal_types';
type SetupServerReturn = Awaited<ReturnType<typeof setupServer>>;
let coreUsageStatsClient: jest.Mocked<CoreUsageStatsClient>;
@ -49,7 +50,7 @@ describe('POST /api/dashboards/import', () => {
beforeEach(async () => {
({ server, httpSetup } = await setupServer());
const router = httpSetup.createRouter('');
const router = httpSetup.createRouter<InternalSavedObjectsRequestHandlerContext>('');
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementLegacyDashboardsImport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail

View file

@ -6,12 +6,12 @@
* Side Public License, v 1.
*/
import { IRouter } from '../../http';
import { IKibanaMigrator } from '../migrations';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
export const registerMigrateRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
migratorPromise: Promise<IKibanaMigrator>
) => {
router.post(

View file

@ -7,14 +7,17 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { InternalSavedObjectRouter } from '../internal_types';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerResolveRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerResolveRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.get(
{
path: '/resolve/{type}/{id}',

View file

@ -10,11 +10,12 @@ import { extname } from 'path';
import { Readable } from 'stream';
import { schema } from '@kbn/config-schema';
import { chain } from 'lodash';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import { SavedObjectConfig } from '../saved_objects_config';
import { SavedObjectsImportError } from '../import';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors, createSavedObjectsStreamFromNdJson } from './utils';
interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
@ -27,7 +28,7 @@ interface FileStream extends Readable {
}
export const registerResolveImportErrorsRoute = (
router: IRouter,
router: InternalSavedObjectRouter,
{ config, coreUsageData }: RouteDependencies
) => {
const { maxImportPayloadBytes } = config;

View file

@ -11,6 +11,7 @@ import { ContextService } from '../../context';
import { createHttpServer, createCoreContext } from '../../http/test_utils';
import { contextServiceMock, coreMock } from '../../mocks';
import { SavedObjectsType } from '../types';
import { InternalSavedObjectsRequestHandlerContext } from '../internal_types';
const defaultCoreId = Symbol('core');
@ -26,9 +27,13 @@ export const setupServer = async (coreId: symbol = defaultCoreId) => {
});
const handlerContext = coreMock.createRequestHandlerContext();
httpSetup.registerRouteHandlerContext(coreId, 'core', async (ctx, req, res) => {
return handlerContext;
});
httpSetup.registerRouteHandlerContext<InternalSavedObjectsRequestHandlerContext, 'core'>(
coreId,
'core',
(ctx, req, res) => {
return handlerContext;
}
);
return {
server,

View file

@ -7,16 +7,19 @@
*/
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { InternalCoreUsageDataSetup } from '../../core_usage_data';
import type { SavedObjectsUpdateOptions } from '../service/saved_objects_client';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors } from './utils';
interface RouteDependencies {
coreUsageData: InternalCoreUsageDataSetup;
}
export const registerUpdateRoute = (router: IRouter, { coreUsageData }: RouteDependencies) => {
export const registerUpdateRoute = (
router: InternalSavedObjectRouter,
{ coreUsageData }: RouteDependencies
) => {
router.put(
{
path: '/{type}/{id}',

View file

@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { KibanaRequest } from '../http';
import type { InternalSavedObjectsServiceStart } from './saved_objects_service';
import type { ISavedObjectTypeRegistry } from './saved_objects_type_registry';
import type { SavedObjectsClientContract } from './types';
import type { SavedObjectsClientProviderOptions } from './service';
import type { ISavedObjectsExporter } from './export';
import type { ISavedObjectsImporter } from './import';
/**
* Core's `savedObjects` request handler context.
* @public
*/
export interface SavedObjectsRequestHandlerContext {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;
getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;
}
/**
* The {@link SavedObjectsRequestHandlerContext} implementation.
* @internal
*/
export class CoreSavedObjectsRouteHandlerContext implements SavedObjectsRequestHandlerContext {
constructor(
private readonly savedObjectsStart: InternalSavedObjectsServiceStart,
private readonly request: KibanaRequest
) {}
#scopedSavedObjectsClient?: SavedObjectsClientContract;
#typeRegistry?: ISavedObjectTypeRegistry;
public get client() {
if (this.#scopedSavedObjectsClient == null) {
this.#scopedSavedObjectsClient = this.savedObjectsStart.getScopedClient(this.request);
}
return this.#scopedSavedObjectsClient;
}
public get typeRegistry() {
if (this.#typeRegistry == null) {
this.#typeRegistry = this.savedObjectsStart.getTypeRegistry();
}
return this.#typeRegistry;
}
public getClient = (options?: SavedObjectsClientProviderOptions) => {
if (!options) return this.client;
return this.savedObjectsStart.getScopedClient(this.request, options);
};
public getExporter = (client: SavedObjectsClientContract) => {
return this.savedObjectsStart.createExporter(client);
};
public getImporter = (client: SavedObjectsClientContract) => {
return this.savedObjectsStart.createImporter(client);
};
}

View file

@ -57,6 +57,7 @@ import { CoreRouteHandlerContext } from './core_route_handler_context';
import { PrebootCoreRouteHandlerContext } from './preboot_core_route_handler_context';
import { PrebootService } from './preboot';
import { DiscoveredPlugins } from './plugins';
import type { RequestHandlerContext, PrebootRequestHandlerContext } from '.';
const coreId = Symbol('core');
const rootConfigPath = '';
@ -208,9 +209,13 @@ export class Server {
await this.plugins.preboot(corePreboot);
httpPreboot.registerRouteHandlerContext(coreId, 'core', (() => {
return new PrebootCoreRouteHandlerContext(corePreboot);
}) as any);
httpPreboot.registerRouteHandlerContext<PrebootRequestHandlerContext, 'core'>(
coreId,
'core',
() => {
return new PrebootCoreRouteHandlerContext(corePreboot);
}
);
this.coreApp.preboot(corePreboot, uiPlugins);
@ -413,9 +418,13 @@ export class Server {
}
private registerCoreContext(coreSetup: InternalCoreSetup) {
coreSetup.http.registerRouteHandlerContext(coreId, 'core', async (context, req, res) => {
return new CoreRouteHandlerContext(this.coreStart!, req);
});
coreSetup.http.registerRouteHandlerContext<RequestHandlerContext, 'core'>(
coreId,
'core',
(context, req) => {
return new CoreRouteHandlerContext(this.coreStart!, req);
}
);
}
public setupCoreConfig() {

View file

@ -10,6 +10,8 @@ export type { UiSettingsClient, UiSettingsServiceOptions } from './ui_settings_c
export { config } from './ui_settings_config';
export { UiSettingsService } from './ui_settings_service';
export { CoreUiSettingsRouteHandlerContext } from './ui_settings_route_handler_context';
export type { UiSettingsRequestHandlerContext } from './ui_settings_route_handler_context';
export type {
UiSettingsServiceSetup,

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { RequestHandlerContextBase } from '..';
import type { IRouter } from '../http';
import type { UiSettingsRequestHandlerContext } from './ui_settings_route_handler_context';
/**
* Request handler context used by core's uiSetting routes.
* @internal
*/
export interface InternalUiSettingsRequestHandlerContext extends RequestHandlerContextBase {
core: Promise<{
uiSettings: UiSettingsRequestHandlerContext;
}>;
}
/**
* Router bound to the {@link InternalUiSettingsRequestHandlerContext}.
* Used by core's uiSetting routes.
* @internal
*/
export type InternalUiSettingsRouter = IRouter<InternalUiSettingsRequestHandlerContext>;

View file

@ -8,8 +8,8 @@
import { schema } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import type { InternalUiSettingsRouter } from '../internal_types';
import { CannotOverrideError } from '../ui_settings_errors';
const validate = {
@ -18,7 +18,7 @@ const validate = {
}),
};
export function registerDeleteRoute(router: IRouter) {
export function registerDeleteRoute(router: InternalUiSettingsRouter) {
router.delete(
{ path: '/api/kibana/settings/{key}', validate },
async (context, request, response) => {

View file

@ -6,10 +6,10 @@
* Side Public License, v 1.
*/
import { IRouter } from '../../http';
import type { InternalUiSettingsRouter } from '../internal_types';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
export function registerGetRoute(router: IRouter) {
export function registerGetRoute(router: InternalUiSettingsRouter) {
router.get(
{ path: '/api/kibana/settings', validate: false },
async (context, request, response) => {

View file

@ -6,14 +6,13 @@
* Side Public License, v 1.
*/
import { IRouter } from '../..';
import type { InternalUiSettingsRouter } from '../internal_types';
import { registerDeleteRoute } from './delete';
import { registerGetRoute } from './get';
import { registerSetManyRoute } from './set_many';
import { registerSetRoute } from './set';
export function registerRoutes(router: IRouter) {
export function registerRoutes(router: InternalUiSettingsRouter) {
registerGetRoute(router);
registerDeleteRoute(router);
registerSetRoute(router);

View file

@ -8,8 +8,8 @@
import { schema, ValidationError } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import type { InternalUiSettingsRouter } from '../internal_types';
import { CannotOverrideError } from '../ui_settings_errors';
const validate = {
@ -21,7 +21,7 @@ const validate = {
}),
};
export function registerSetRoute(router: IRouter) {
export function registerSetRoute(router: InternalUiSettingsRouter) {
router.post(
{ path: '/api/kibana/settings/{key}', validate },
async (context, request, response) => {

View file

@ -8,8 +8,8 @@
import { schema, ValidationError } from '@kbn/config-schema';
import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import type { InternalUiSettingsRouter } from '../internal_types';
import { CannotOverrideError } from '../ui_settings_errors';
const validate = {
@ -18,7 +18,7 @@ const validate = {
}),
};
export function registerSetManyRoute(router: IRouter) {
export function registerSetManyRoute(router: InternalUiSettingsRouter) {
router.post({ path: '/api/kibana/settings', validate }, async (context, request, response) => {
try {
const uiSettingsClient = (await context.core).uiSettings.client;

View file

@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { CoreSavedObjectsRouteHandlerContext } from '../saved_objects';
import type { IUiSettingsClient, InternalUiSettingsServiceStart } from './types';
/**
* Core's `uiSettings` request handler context.
* @public
*/
export interface UiSettingsRequestHandlerContext {
client: IUiSettingsClient;
}
/**
* The {@link UiSettingsRequestHandlerContext} implementation.
* @internal
*/
export class CoreUiSettingsRouteHandlerContext implements UiSettingsRequestHandlerContext {
#client?: IUiSettingsClient;
constructor(
private readonly uiSettingsStart: InternalUiSettingsServiceStart,
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext
) {}
public get client() {
if (this.#client == null) {
this.#client = this.uiSettingsStart.asScopedToClient(
this.savedObjectsRouterHandlerContext.client
);
}
return this.#client;
}
}

View file

@ -26,6 +26,7 @@ import { uiSettingsType } from './saved_objects';
import { registerRoutes } from './routes';
import { getCoreSettings } from './settings';
import { UiSettingsDefaultsClient } from './ui_settings_defaults_client';
import type { InternalUiSettingsRequestHandlerContext } from './internal_types';
export interface SetupDeps {
http: InternalHttpServiceSetup;
@ -70,7 +71,7 @@ export class UiSettingsService
this.log.debug('Setting up ui settings service');
savedObjects.registerType(uiSettingsType);
registerRoutes(http.createRouter(''));
registerRoutes(http.createRouter<InternalUiSettingsRequestHandlerContext>(''));
const config = await firstValueFrom(this.config$);
this.overrides = config.overrides;

View file

@ -8,7 +8,12 @@
import { BehaviorSubject } from 'rxjs';
import { MetricsServiceSetup, ServiceStatus, ServiceStatusLevels } from '@kbn/core/server';
import {
MetricsServiceSetup,
RequestHandlerContext,
ServiceStatus,
ServiceStatusLevels,
} from '@kbn/core/server';
import {
contextServiceMock,
loggingSystemMock,
@ -42,7 +47,7 @@ describe('/api/stats', () => {
});
metrics = metricsServiceMock.createSetupContract();
const router = httpSetup.createRouter('');
const router = httpSetup.createRouter<RequestHandlerContext>('');
registerStatsRoute({
router,
collectorSet: new CollectorSet({

View file

@ -57,12 +57,12 @@ export class License {
});
}
guardApiRoute(handler: RequestHandler) {
guardApiRoute<P, Q, B>(handler: RequestHandler<P, Q, B>) {
const license = this;
return function licenseCheck(
ctx: RequestHandlerContext,
request: KibanaRequest,
request: KibanaRequest<P, Q, B>,
response: KibanaResponseFactory
) {
const licenseStatus = license.getStatus();

View file

@ -8,7 +8,7 @@
import Boom from '@hapi/boom';
// @ts-ignore
import type { CoreSetup, IBasePath, IRouter } from '@kbn/core/server';
import type { CoreSetup, IBasePath, IRouter, RequestHandlerContext } from '@kbn/core/server';
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
import { coreMock, elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks';
import * as kbnTestServer from '@kbn/core/test_helpers/kbn_server';
@ -153,7 +153,7 @@ describe.skip('onPostAuthInterceptor', () => {
getSpacesService: () => spacesServiceStart,
});
const router = http.createRouter('/');
const router = http.createRouter<RequestHandlerContext>('/');
initKbnServer(router, http.basePath);

View file

@ -12,6 +12,7 @@ import type {
IRouter,
KibanaRequest,
KibanaResponseFactory,
RequestHandlerContext,
} from '@kbn/core/server';
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
import * as kbnTestServer from '@kbn/core/test_helpers/kbn_server';
@ -89,7 +90,7 @@ describe.skip('onRequestInterceptor', () => {
http: http as unknown as CoreSetup['http'],
});
const router = http.createRouter('/');
const router = http.createRouter<RequestHandlerContext>('/');
initKbnServer(router, http.basePath);