From b33f6071bcf3e60d9202887a2963c63c3b2db5a0 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 11:22:19 +0200 Subject: [PATCH 1/9] updated router types --- .../http/core-http-server/src/router/route.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index a97ff9dd4040b..501062f78d235 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -321,6 +321,22 @@ export interface RouteConfigOptions { * @default false */ httpResource?: boolean; + + /** + * Based on the the ES API specification (see https://github.com/elastic/elasticsearch-specification) + * Kibana APIs can also specify some metadata about API availability. + * + * @remark intended to be used for informational purposes only. + * + */ + availability?: { + /** @default stable */ + stability?: 'experimental' | 'beta' | 'stable'; + /** + * Must be a stack version + */ + since?: string; + }; } /** From ed1e333c518a364eaf4eea45680b691a7e165052 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 11:22:59 +0200 Subject: [PATCH 2/9] updated tests to check that metadata is being passed through --- .../src/router.test.ts | 8 ++++ .../core_versioned_route.test.ts | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/packages/core/http/core-http-router-server-internal/src/router.test.ts b/packages/core/http/core-http-router-server-internal/src/router.test.ts index c318e9312546a..f611e3b6308fe 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.test.ts @@ -54,6 +54,10 @@ describe('Router', () => { discontinued: 'post test discontinued', summary: 'post test summary', description: 'post test description', + availability: { + since: '1.0.0', + stability: 'experimental', + }, }, }, (context, req, res) => res.ok() @@ -72,6 +76,10 @@ describe('Router', () => { discontinued: 'post test discontinued', summary: 'post test summary', description: 'post test description', + availability: { + since: '1.0.0', + stability: 'experimental', + }, }, }); }); diff --git a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts index 3938b8addfc25..16c84034fa3f1 100644 --- a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts @@ -52,6 +52,46 @@ describe('Versioned route', () => { jest.clearAllMocks(); }); + describe('#getRoutes', () => { + it('returns the expected metadata', () => { + const versionedRouter = CoreVersionedRouter.from({ router }); + versionedRouter + .get({ + path: '/test/{id}', + access: 'public', + options: { + httpResource: true, + availability: { + since: '1.0.0', + stability: 'experimental', + }, + excludeFromOAS: true, + tags: ['1', '2', '3'], + }, + description: 'test', + summary: 'test', + enableQueryVersion: false, + }) + .addVersion({ version: '2023-10-31', validate: false }, handlerFn); + + expect(versionedRouter.getRoutes()[0].options).toMatchObject({ + access: 'public', + enableQueryVersion: false, + description: 'test', + summary: 'test', + options: { + httpResource: true, + availability: { + since: '1.0.0', + stability: 'experimental', + }, + excludeFromOAS: true, + tags: ['1', '2', '3'], + }, + }); + }); + }); + it('can register multiple handlers', () => { const versionedRouter = CoreVersionedRouter.from({ router }); versionedRouter From 4254559337435f2977266983c154e060f0a71437 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 11:23:13 +0200 Subject: [PATCH 3/9] fix minor type bug --- packages/core/http/core-http-server/src/versioning/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/http/core-http-server/src/versioning/types.ts b/packages/core/http/core-http-server/src/versioning/types.ts index 60cbca014e683..7998c9cc91fa9 100644 --- a/packages/core/http/core-http-server/src/versioning/types.ts +++ b/packages/core/http/core-http-server/src/versioning/types.ts @@ -35,7 +35,7 @@ export type VersionedRouteConfig = Omit< > & { options?: Omit< RouteConfigOptions, - 'access' | 'description' | 'deprecated' | 'discontinued' | 'security' + 'access' | 'description' | 'summary' | 'deprecated' | 'discontinued' | 'security' >; /** See {@link RouteConfigOptions['access']} */ access: Exclude['access'], undefined>; From e03d4d20e1093f0fc8148f0a513a94ab90813bd8 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 11:23:31 +0200 Subject: [PATCH 4/9] fix typo --- packages/kbn-router-to-openapispec/openapi-types.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-router-to-openapispec/openapi-types.d.ts b/packages/kbn-router-to-openapispec/openapi-types.d.ts index 90c034a855fdc..9689ed803a152 100644 --- a/packages/kbn-router-to-openapispec/openapi-types.d.ts +++ b/packages/kbn-router-to-openapispec/openapi-types.d.ts @@ -13,7 +13,7 @@ export * from 'openapi-types'; declare module 'openapi-types' { export namespace OpenAPIV3 { export interface BaseSchemaObject { - // Custom OpenAPI field added by Kibana for a new field at the shema level. + // Custom OpenAPI field added by Kibana for a new field at the schema level. 'x-discontinued'?: string; } } From 60be4e4ba5d77c56f5ff369afdeaf3fd9b98274f Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 11:23:49 +0200 Subject: [PATCH 5/9] added integration level test for availability --- .../src/generate_oas.test.ts | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/packages/kbn-router-to-openapispec/src/generate_oas.test.ts b/packages/kbn-router-to-openapispec/src/generate_oas.test.ts index 6db4237751217..c3532312d3088 100644 --- a/packages/kbn-router-to-openapispec/src/generate_oas.test.ts +++ b/packages/kbn-router-to-openapispec/src/generate_oas.test.ts @@ -321,4 +321,103 @@ describe('generateOpenApiDocument', () => { expect(result.paths['/v2-1']!.get!.tags).toEqual([]); }); }); + + describe('availability', () => { + it('creates the expected availability entries', () => { + const [routers, versionedRouters] = createTestRouters({ + routers: { + testRouter1: { + routes: [ + { + path: '/1-1/{id}/{path*}', + options: { availability: { stability: 'experimental' } }, + }, + { + path: '/1-2/{id}/{path*}', + options: { availability: { stability: 'beta' } }, + }, + { + path: '/1-3/{id}/{path*}', + options: { availability: { stability: 'stable' } }, + }, + ], + }, + testRouter2: { + routes: [{ path: '/2-1/{id}/{path*}' }], + }, + }, + versionedRouters: { + testVersionedRouter1: { + routes: [ + { + path: '/v1-1', + options: { + access: 'public', + options: { availability: { stability: 'experimental' } }, + }, + }, + { + path: '/v1-2', + options: { + access: 'public', + options: { availability: { stability: 'beta' } }, + }, + }, + { + path: '/v1-3', + options: { + access: 'public', + options: { availability: { stability: 'stable' } }, + }, + }, + ], + }, + testVersionedRouter2: { + routes: [{ path: '/v2-1', options: { access: 'public' } }], + }, + }, + }); + const result = generateOpenApiDocument( + { + routers, + versionedRouters, + }, + { + title: 'test', + baseUrl: 'https://test.oas', + version: '99.99.99', + } + ); + + // router paths + expect(result.paths['/1-1/{id}/{path*}']!.get).toMatchObject({ + 'x-state': 'Technical Preview', + }); + expect(result.paths['/1-2/{id}/{path*}']!.get).toMatchObject({ + 'x-state': 'Beta', + }); + + expect(result.paths['/1-3/{id}/{path*}']!.get).not.toMatchObject({ + 'x-state': expect.any(String), + }); + expect(result.paths['/2-1/{id}/{path*}']!.get).not.toMatchObject({ + 'x-state': expect.any(String), + }); + + // versioned router paths + expect(result.paths['/v1-1']!.get).toMatchObject({ + 'x-state': 'Technical Preview', + }); + expect(result.paths['/v1-2']!.get).toMatchObject({ + 'x-state': 'Beta', + }); + + expect(result.paths['/v1-3']!.get).not.toMatchObject({ + 'x-state': expect.any(String), + }); + expect(result.paths['/v2-1']!.get).not.toMatchObject({ + 'x-state': expect.any(String), + }); + }); + }); }); From 58d13de8f4f84ce2901d9c5a3a2673ac984b63e9 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 11:24:14 +0200 Subject: [PATCH 6/9] set x-state --- .../src/process_router.ts | 6 +++++- .../src/process_versioned_router.ts | 4 ++++ packages/kbn-router-to-openapispec/src/type.ts | 5 +++++ packages/kbn-router-to-openapispec/src/util.ts | 16 +++++++++++++++- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/kbn-router-to-openapispec/src/process_router.ts b/packages/kbn-router-to-openapispec/src/process_router.ts index 4437e35ea1f3e..1884b6dddf863 100644 --- a/packages/kbn-router-to-openapispec/src/process_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_router.ts @@ -23,9 +23,11 @@ import { getVersionedHeaderParam, mergeResponseContent, prepareRoutes, + setXState, } from './util'; import type { OperationIdCounter } from './operation_id_counter'; import type { GenerateOpenApiDocumentOptionsFilters } from './generate_oas'; +import type { CustomOperationObject } from './type'; export const processRouter = ( appRouter: Router, @@ -61,7 +63,7 @@ export const processRouter = ( parameters.push(...pathObjects, ...queryObjects); } - const operation: OpenAPIV3.OperationObject = { + const operation: CustomOperationObject = { summary: route.options.summary ?? '', tags: route.options.tags ? extractTags(route.options.tags) : [], ...(route.options.description ? { description: route.options.description } : {}), @@ -81,6 +83,8 @@ export const processRouter = ( operationId: getOpId(route.path), }; + setXState(route.options.availability, operation); + const path: OpenAPIV3.PathItemObject = { [route.method]: operation, }; diff --git a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts index 97b92f92fde57..5446f1409760d 100644 --- a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts @@ -29,6 +29,7 @@ import { extractTags, mergeResponseContent, getXsrfHeaderForMethod, + setXState, } from './util'; export const processVersionedRouter = ( @@ -112,6 +113,9 @@ export const processVersionedRouter = ( parameters, operationId: getOpId(route.path), }; + + setXState(route.options.options?.availability, operation); + const path: OpenAPIV3.PathItemObject = { [route.method]: operation, }; diff --git a/packages/kbn-router-to-openapispec/src/type.ts b/packages/kbn-router-to-openapispec/src/type.ts index 09dc247e5a5c9..5c5f992a0de0f 100644 --- a/packages/kbn-router-to-openapispec/src/type.ts +++ b/packages/kbn-router-to-openapispec/src/type.ts @@ -34,3 +34,8 @@ export interface OpenAPIConverter { is(type: unknown): boolean; } + +export type CustomOperationObject = OpenAPIV3.OperationObject<{ + // Custom OpenAPI from ES API spec based on @availability + 'x-state'?: 'Technical Preview' | 'Beta'; +}>; diff --git a/packages/kbn-router-to-openapispec/src/util.ts b/packages/kbn-router-to-openapispec/src/util.ts index 55f7348dc199a..beefbebc0aec7 100644 --- a/packages/kbn-router-to-openapispec/src/util.ts +++ b/packages/kbn-router-to-openapispec/src/util.ts @@ -17,7 +17,7 @@ import { type RouterRoute, type RouteValidatorConfig, } from '@kbn/core-http-server'; -import { KnownParameters } from './type'; +import { CustomOperationObject, KnownParameters } from './type'; import type { GenerateOpenApiDocumentOptionsFilters } from './generate_oas'; const tagPrefix = 'oas-tag:'; @@ -165,3 +165,17 @@ export const getXsrfHeaderForMethod = ( }, ]; }; + +export function setXState( + availability: RouteConfigOptions['availability'], + operation: CustomOperationObject +): void { + if (availability) { + if (availability.stability === 'experimental') { + operation['x-state'] = 'Technical Preview'; + } + if (availability.stability === 'beta') { + operation['x-state'] = 'Beta'; + } + } +} From a783311c461c8e42a8771ac81a1bc3c31e090244 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 17 Oct 2024 14:23:33 +0200 Subject: [PATCH 7/9] fix types --- .../src/versioned_router/core_versioned_route.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts index 16c84034fa3f1..1442467012d8b 100644 --- a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts @@ -173,6 +173,8 @@ describe('Versioned route', () => { const opts: Parameters[0] = { path: '/test/{id}', access: 'internal', + summary: 'test', + description: 'test', options: { authRequired: true, tags: ['access:test'], @@ -180,7 +182,6 @@ describe('Versioned route', () => { xsrfRequired: false, excludeFromOAS: true, httpResource: true, - summary: `test`, }, }; From 6fe22e6f50bb7607f96cd31cdf5e626c25c5f357 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Fri, 18 Oct 2024 11:08:19 +0200 Subject: [PATCH 8/9] Update packages/core/http/core-http-server/src/router/route.ts Co-authored-by: Christiane (Tina) Heiligers --- packages/core/http/core-http-server/src/router/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index 501062f78d235..79c5b0ffcc702 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -333,7 +333,7 @@ export interface RouteConfigOptions { /** @default stable */ stability?: 'experimental' | 'beta' | 'stable'; /** - * Must be a stack version + * The stack version in which the route was introduced (eg: 8.15.0). */ since?: string; }; From 251b5ce4dc44d5868a5d045dc0abb913bd33843b Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Fri, 18 Oct 2024 11:10:44 +0200 Subject: [PATCH 9/9] updated comment --- packages/core/http/core-http-server/src/router/route.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index 79c5b0ffcc702..ac723db924a5a 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -326,8 +326,9 @@ export interface RouteConfigOptions { * Based on the the ES API specification (see https://github.com/elastic/elasticsearch-specification) * Kibana APIs can also specify some metadata about API availability. * - * @remark intended to be used for informational purposes only. + * This setting is only applicable if your route `access` is `public`. * + * @remark intended to be used for informational purposes only. */ availability?: { /** @default stable */