Skip to content

Commit

Permalink
[8.x] [OAS] Support setting availability (#196647) (#197394)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [[OAS] Support setting availability
(#196647)](#196647)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Jean-Louis
Leysens","email":"jeanlouis.leysens@elastic.co"},"sourceCommit":{"committedDate":"2024-10-21T10:30:45Z","message":"[OAS]
Support setting availability (#196647)\n\n## Summary\r\n\r\nClose
https://github.com/elastic/kibana/issues/181995\r\n\r\nRelated
https://github.com/elastic/kibana/pull/195325\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Christiane (Tina)
Heiligers
<christiane.heiligers@elastic.co>","sha":"608cc70be56fa63cb68a93d480e545fa95c0846a","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Core","release_note:skip","v9.0.0","Feature:OAS","v8.16.0","backport:version","v8.17.0"],"number":196647,"url":"https://github.com/elastic/kibana/pull/196647","mergeCommit":{"message":"[OAS]
Support setting availability (#196647)\n\n## Summary\r\n\r\nClose
https://github.com/elastic/kibana/issues/181995\r\n\r\nRelated
https://github.com/elastic/kibana/pull/195325\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Christiane (Tina)
Heiligers
<christiane.heiligers@elastic.co>","sha":"608cc70be56fa63cb68a93d480e545fa95c0846a"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/196647","number":196647,"mergeCommit":{"message":"[OAS]
Support setting availability (#196647)\n\n## Summary\r\n\r\nClose
https://github.com/elastic/kibana/issues/181995\r\n\r\nRelated
https://github.com/elastic/kibana/pull/195325\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Christiane (Tina)
Heiligers
<christiane.heiligers@elastic.co>","sha":"608cc70be56fa63cb68a93d480e545fa95c0846a"}},{"branch":"8.16","label":"v8.16.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/197025","number":197025,"state":"MERGED","mergeCommit":{"sha":"76993eb1f6b160a9f58377fee967c3b578023f5b","message":"[8.16]
[OAS] Support setting availability (#196647) (#197025)\n\n#
Backport\n\nThis will backport the following commits from `main` to
`8.16`:\n- [[OAS] Support setting
availability\n(#196647)](https://github.com/elastic/kibana/pull/196647)\n\n<!---
Backport version: 9.4.3 -->\n\n### Questions ?\nPlease refer to the
[Backport
tool\ndocumentation](https://github.com/sqren/backport)\n\n<!--BACKPORT
[{\"author\":{\"name\":\"Jean-Louis\nLeysens\",\"email\":\"jeanlouis.leysens@elastic.co\"},\"sourceCommit\":{\"committedDate\":\"2024-10-21T10:30:45Z\",\"message\":\"[OAS]\nSupport
setting availability (#196647)\\n\\n##
Summary\\r\\n\\r\\nClose\nhttps://github.com//issues/181995\\r\\n\\r\\nRelated\nhttps://github.com//pull/195325\\r\\n\\r\\n\\r\\n###\nChecklist\\r\\n\\r\\n-
[x] [Unit
or\nfunctional\\r\\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\\r\\nwere\nupdated
or added to match the most
common\nscenarios\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by:
Christiane
(Tina)\nHeiligers\n<christiane.heiligers@elastic.co>\",\"sha\":\"608cc70be56fa63cb68a93d480e545fa95c0846a\",\"branchLabelMapping\":{\"^v9.0.0$\":\"main\",\"^v8.17.0$\":\"8.x\",\"^v(\\\\d+).(\\\\d+).\\\\d+$\":\"$1.$2\"}},\"sourcePullRequest\":{\"labels\":[\"Team:Core\",\"release_note:skip\",\"v9.0.0\",\"Feature:OAS\",\"v8.16.0\",\"backport:version\"],\"title\":\"[OAS]\nSupport
setting\navailability\",\"number\":196647,\"url\":\"https://github.com/elastic/kibana/pull/196647\",\"mergeCommit\":{\"message\":\"[OAS]\nSupport
setting availability (#196647)\\n\\n##
Summary\\r\\n\\r\\nClose\nhttps://github.com//issues/181995\\r\\n\\r\\nRelated\nhttps://github.com//pull/195325\\r\\n\\r\\n\\r\\n###\nChecklist\\r\\n\\r\\n-
[x] [Unit
or\nfunctional\\r\\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\\r\\nwere\nupdated
or added to match the most
common\nscenarios\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by:
Christiane
(Tina)\nHeiligers\n<christiane.heiligers@elastic.co>\",\"sha\":\"608cc70be56fa63cb68a93d480e545fa95c0846a\"}},\"sourceBranch\":\"main\",\"suggestedTargetBranches\":[\"8.16\"],\"targetPullRequestStates\":[{\"branch\":\"main\",\"label\":\"v9.0.0\",\"branchLabelMappingKey\":\"^v9.0.0$\",\"isSourceBranch\":true,\"state\":\"MERGED\",\"url\":\"https://github.com/elastic/kibana/pull/196647\",\"number\":196647,\"mergeCommit\":{\"message\":\"[OAS]\nSupport
setting availability (#196647)\\n\\n##
Summary\\r\\n\\r\\nClose\nhttps://github.com//issues/181995\\r\\n\\r\\nRelated\nhttps://github.com//pull/195325\\r\\n\\r\\n\\r\\n###\nChecklist\\r\\n\\r\\n-
[x] [Unit
or\nfunctional\\r\\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\\r\\nwere\nupdated
or added to match the most
common\nscenarios\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by:
Christiane
(Tina)\nHeiligers\n<christiane.heiligers@elastic.co>\",\"sha\":\"608cc70be56fa63cb68a93d480e545fa95c0846a\"}},{\"branch\":\"8.16\",\"label\":\"v8.16.0\",\"branchLabelMappingKey\":\"^v(\\\\d+).(\\\\d+).\\\\d+$\",\"isSourceBranch\":false,\"state\":\"NOT_CREATED\"}]}]\nBACKPORT-->\n\nCo-authored-by:
Jean-Louis Leysens
<jeanlouis.leysens@elastic.co>"}},{"branch":"8.x","label":"v8.17.0","labelRegex":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
  • Loading branch information
jloleysens authored Oct 23, 2024
1 parent 19dde64 commit b3b8a3e
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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',
},
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -133,14 +173,15 @@ describe('Versioned route', () => {
const opts: Parameters<typeof versionedRouter.post>[0] = {
path: '/test/{id}',
access: 'internal',
summary: 'test',
description: 'test',
options: {
authRequired: true,
tags: ['access:test'],
timeout: { payload: 60_000, idleSocket: 10_000 },
xsrfRequired: false,
excludeFromOAS: true,
httpResource: true,
summary: `test`,
},
};

Expand Down
17 changes: 17 additions & 0 deletions packages/core/http/core-http-server/src/router/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,23 @@ export interface RouteConfigOptions<Method extends RouteMethod> {
* @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.
*
* This setting is only applicable if your route `access` is `public`.
*
* @remark intended to be used for informational purposes only.
*/
availability?: {
/** @default stable */
stability?: 'experimental' | 'beta' | 'stable';
/**
* The stack version in which the route was introduced (eg: 8.15.0).
*/
since?: string;
};
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type VersionedRouteConfig<Method extends RouteMethod> = Omit<
> & {
options?: Omit<
RouteConfigOptions<Method>,
'access' | 'description' | 'deprecated' | 'discontinued' | 'security'
'access' | 'description' | 'summary' | 'deprecated' | 'discontinued' | 'security'
>;
/** See {@link RouteConfigOptions<RouteMethod>['access']} */
access: Exclude<RouteConfigOptions<Method>['access'], undefined>;
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-router-to-openapispec/openapi-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
99 changes: 99 additions & 0 deletions packages/kbn-router-to-openapispec/src/generate_oas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
});
});
});
});
6 changes: 5 additions & 1 deletion packages/kbn-router-to-openapispec/src/process_router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 } : {}),
Expand All @@ -81,6 +83,8 @@ export const processRouter = (
operationId: getOpId(route.path),
};

setXState(route.options.availability, operation);

const path: OpenAPIV3.PathItemObject = {
[route.method]: operation,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
extractTags,
mergeResponseContent,
getXsrfHeaderForMethod,
setXState,
} from './util';

export const processVersionedRouter = (
Expand Down Expand Up @@ -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,
};
Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-router-to-openapispec/src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}>;
16 changes: 15 additions & 1 deletion packages/kbn-router-to-openapispec/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:';
Expand Down Expand Up @@ -165,3 +165,17 @@ export const getXsrfHeaderForMethod = (
},
];
};

export function setXState(
availability: RouteConfigOptions<RouteMethod>['availability'],
operation: CustomOperationObject
): void {
if (availability) {
if (availability.stability === 'experimental') {
operation['x-state'] = 'Technical Preview';
}
if (availability.stability === 'beta') {
operation['x-state'] = 'Beta';
}
}
}

0 comments on commit b3b8a3e

Please sign in to comment.