mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[HTTP/OAS] Sort OpenAPI tags by x-displayName
when it is set (#191732)
**Relates to:** https://github.com/elastic/kibana/issues/186356 ## Summary This PR implements proper tags sorting when a custom tag's `x-displayName` property is set. It allows to display tags properly at the API reference documentation page where `x-displayName` instead of tag's name when it's presented.
This commit is contained in:
parent
fd084d97f7
commit
3c4e50249d
5 changed files with 216 additions and 3 deletions
|
@ -725,6 +725,65 @@ paths:
|
|||
type: object
|
||||
```
|
||||
|
||||
### Root level tags with `x-displayName`
|
||||
|
||||
OpenAPI documents may have root level tags referenced by name in operations. Some platforms including Bump.sh used for API reference documentation support `x-displayName`. Value specified in that custom property used instead of `tag.name` to display a name.
|
||||
|
||||
OpenAPI bundler supports `x-displayName` as well.
|
||||
|
||||
#### Examples
|
||||
|
||||
To specify a custom tag with `x-displayName` to assign that tag to all operations in the document the following configuration should be specified
|
||||
|
||||
```bash
|
||||
const { bundle } = require('@kbn/openapi-bundler');
|
||||
const { join, resolve } = require('path');
|
||||
|
||||
const ROOT = resolve(__dirname, '../..');
|
||||
|
||||
(async () => {
|
||||
await bundle({
|
||||
// ...
|
||||
options: {
|
||||
prototypeDocument: {
|
||||
tags: [
|
||||
{
|
||||
name: 'My tag name',
|
||||
description: 'My tag description',
|
||||
x-displayName: 'My Custom Name',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
It will produce a document containing the specified tag assigned to all operations like below
|
||||
|
||||
```yaml
|
||||
openapi: 3.0.3
|
||||
info: ...
|
||||
servers: ...
|
||||
paths:
|
||||
/api/some/operation:
|
||||
delete:
|
||||
operationId: SomeOperation
|
||||
...
|
||||
tags:
|
||||
- My tag name
|
||||
- Tag existing before bundling
|
||||
components:
|
||||
schemas: ...
|
||||
security: ...
|
||||
tags:
|
||||
- description: My tag description
|
||||
name: My tag name
|
||||
x-displayName: My Custom Name
|
||||
```
|
||||
|
||||
When merging OpenAPI specs together tags will be sorted by `x-displayName` or `name` in ascending order depending on whether `x-displayName` is specified.
|
||||
|
||||
## Contribution
|
||||
|
||||
In case you decide to contribute to the `kbn-openapi-bundler` package please make sure to add and/or update existing e2e test in `kbn-openapi-bundler/tests` folder.
|
||||
|
|
|
@ -25,7 +25,13 @@ export function mergeTags(
|
|||
|
||||
// To streamline API endpoints categorization it's expected that
|
||||
// tags are sorted alphabetically by name
|
||||
merged.sort((a, b) => a.name.localeCompare(b.name));
|
||||
merged.sort((a, b) => getTagName(a).localeCompare(getTagName(b)));
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
function getTagName(tag: OpenAPIV3.TagObject): string {
|
||||
return 'x-displayName' in tag && typeof tag['x-displayName'] === 'string'
|
||||
? tag['x-displayName']
|
||||
: tag.name;
|
||||
}
|
||||
|
|
20
packages/kbn-openapi-bundler/src/openapi_types.ts
Normal file
20
packages/kbn-openapi-bundler/src/openapi_types.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 'openapi-types';
|
||||
|
||||
// Override the OpenAPI types to add the x-displayName property to the
|
||||
// tag object.
|
||||
declare module 'openapi-types' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace OpenAPIV3 {
|
||||
interface TagObject {
|
||||
'x-displayName'?: string;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -179,4 +179,77 @@ describe('OpenAPI Bundler - assign a tag', () => {
|
|||
{ name: 'Global tag', description: 'Global tag description' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('supports x-displayName', async () => {
|
||||
const spec1 = createOASDocument({
|
||||
paths: {
|
||||
'/api/some_api': {
|
||||
get: {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Successful response',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const spec2 = createOASDocument({
|
||||
paths: {
|
||||
'/api/another_api': {
|
||||
get: {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Successful response',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const [bundledSpec] = Object.values(
|
||||
await bundleSpecs(
|
||||
{
|
||||
1: spec1,
|
||||
2: spec2,
|
||||
},
|
||||
{
|
||||
prototypeDocument: {
|
||||
tags: [
|
||||
{
|
||||
name: 'Some Tag',
|
||||
description: 'Some tag description',
|
||||
'x-displayName': 'Custom name',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
expect(bundledSpec.paths['/api/some_api']?.get?.tags).toEqual(['Some Tag']);
|
||||
expect(bundledSpec.paths['/api/another_api']?.get?.tags).toEqual(['Some Tag']);
|
||||
expect(bundledSpec.tags).toEqual([
|
||||
{
|
||||
name: 'Some Tag',
|
||||
description: 'Some tag description',
|
||||
'x-displayName': 'Custom name',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import { mergeSpecs } from '../merge_specs';
|
||||
import { createOASDocument } from '../../create_oas_document';
|
||||
|
||||
describe('OpenAPI Merger - sort tags', () => {
|
||||
it('sorts tags in the result bundle', async () => {
|
||||
describe('OpenAPI Merger - sort tags in the result bundle', () => {
|
||||
it('sorts tags by name', async () => {
|
||||
const spec1 = createOASDocument({
|
||||
paths: {
|
||||
'/api/some_api': {
|
||||
|
@ -60,4 +60,59 @@ describe('OpenAPI Merger - sort tags', () => {
|
|||
{ name: 'Spec3 tag name', description: 'Spec3 tag description' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts tags by x-displayName or name', async () => {
|
||||
const spec1 = createOASDocument({
|
||||
paths: {
|
||||
'/api/some_api': {
|
||||
get: {
|
||||
responses: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: [
|
||||
{ name: 'Some tag name', description: 'Some description' },
|
||||
{ name: '1 tag', description: 'Some description' },
|
||||
],
|
||||
});
|
||||
const spec2 = createOASDocument({
|
||||
paths: {
|
||||
'/api/some_api': {
|
||||
post: {
|
||||
responses: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: [
|
||||
{ name: 'Another tag name', description: 'Another description', 'x-displayName': 'Y tag' },
|
||||
],
|
||||
});
|
||||
const spec3 = createOASDocument({
|
||||
paths: {
|
||||
'/api/some_api': {
|
||||
put: {
|
||||
responses: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: [
|
||||
{ name: 'Spec3 tag name', description: 'Spec3 tag description', 'x-displayName': 'X tag' },
|
||||
],
|
||||
});
|
||||
|
||||
const [mergedSpec] = Object.values(
|
||||
await mergeSpecs({
|
||||
1: spec1,
|
||||
2: spec2,
|
||||
3: spec3,
|
||||
})
|
||||
);
|
||||
|
||||
expect(mergedSpec.tags).toEqual([
|
||||
{ name: '1 tag', description: 'Some description' },
|
||||
{ name: 'Some tag name', description: 'Some description' },
|
||||
{ name: 'Spec3 tag name', description: 'Spec3 tag description', 'x-displayName': 'X tag' },
|
||||
{ name: 'Another tag name', description: 'Another description', 'x-displayName': 'Y tag' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue