Skip to content

Commit a3f1fea

Browse files
authored
Display OpenAPI header description (#2857)
1 parent bb5c6a4 commit a3f1fea

File tree

5 files changed

+93
-34
lines changed

5 files changed

+93
-34
lines changed

.changeset/green-moles-camp.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@gitbook/react-openapi': patch
3+
---
4+
5+
Fix display of OpenAPI header description

packages/react-openapi/src/OpenAPIResponse.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
22
import { OpenAPISchemaProperties } from './OpenAPISchema';
3-
import { resolveDescription } from './utils';
3+
import { parameterToProperty, resolveDescription } from './utils';
44
import type { OpenAPIClientContext } from './types';
55
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
66

@@ -27,25 +27,19 @@ export function OpenAPIResponse(props: {
2727
return (
2828
<div className="openapi-response-body">
2929
{headers.length > 0 ? (
30-
<OpenAPIDisclosure context={context} label={'Headers'}>
30+
<OpenAPIDisclosure context={context} label="Headers">
3131
<OpenAPISchemaProperties
32-
properties={headers.map(([name, header]) => ({
33-
propertyName: name,
34-
schema: header.schema ?? {},
35-
required: header.required,
36-
}))}
32+
properties={headers.map(([name, header]) => {
33+
return parameterToProperty({ name, ...header });
34+
})}
3735
context={context}
3836
/>
3937
</OpenAPIDisclosure>
4038
) : null}
4139
<div className="openapi-responsebody">
4240
<OpenAPISchemaProperties
4341
id={`response-${context.blockKey}`}
44-
properties={[
45-
{
46-
schema: mediaType.schema ?? {},
47-
},
48-
]}
42+
properties={mediaType.schema ? [{ schema: mediaType.schema }] : []}
4943
context={context}
5044
/>
5145
</div>

packages/react-openapi/src/OpenAPISchema.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { OpenAPIDisclosure } from './OpenAPIDisclosure';
1313
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
1414

1515
export interface OpenAPISchemaPropertyEntry {
16-
propertyName?: string;
17-
required?: boolean;
16+
propertyName?: string | undefined;
17+
required?: boolean | undefined;
1818
schema: OpenAPIV3.SchemaObject;
1919
}
2020

@@ -47,7 +47,7 @@ export function OpenAPISchemaProperty(
4747
? null
4848
: getSchemaAlternatives(schema, new Set(circularRefs.keys()));
4949

50-
if ((properties && !!properties.length) || schema.type === 'object') {
50+
if ((properties && properties.length > 0) || schema.type === 'object') {
5151
return (
5252
<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
5353
<OpenAPISchemaPresentation {...props} />

packages/react-openapi/src/OpenAPISpec.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { OpenAPIResponses } from './OpenAPIResponses';
88
import { OpenAPISchemaProperties } from './OpenAPISchema';
99
import { OpenAPISecurities } from './OpenAPISecurities';
1010
import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
11-
import { resolveDescription } from './utils';
11+
import { parameterToProperty } from './utils';
1212

1313
/**
1414
* Client component to render the spec for the request and response.
@@ -38,22 +38,7 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
3838
header={group.label}
3939
>
4040
<OpenAPISchemaProperties
41-
properties={group.parameters.map((parameter) => {
42-
const description = resolveDescription(parameter);
43-
return {
44-
propertyName: parameter.name,
45-
schema: {
46-
// Description of the parameter is defined at the parameter level
47-
// we use display it if the schema doesn't override it
48-
description: description,
49-
example: parameter.example,
50-
// Deprecated can be defined at the parameter level
51-
deprecated: parameter.deprecated,
52-
...(parameter.schema ?? {}),
53-
},
54-
required: parameter.required,
55-
};
56-
})}
41+
properties={group.parameters.map(parameterToProperty)}
5742
context={context}
5843
/>
5944
</InteractiveSection>

packages/react-openapi/src/utils.ts

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import type { AnyObject, OpenAPIV3 } from '@gitbook/openapi-parser';
1+
import type { AnyObject, OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
22

3-
export function checkIsReference(input: unknown): input is OpenAPIV3.ReferenceObject {
3+
export function checkIsReference(
4+
input: unknown,
5+
): input is OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject {
46
return typeof input === 'object' && !!input && '$ref' in input;
57
}
68

@@ -19,3 +21,76 @@ export function resolveDescription(object: AnyObject) {
1921
? object.description
2022
: undefined;
2123
}
24+
25+
/**
26+
* Extract descriptions from an object.
27+
*/
28+
export function extractDescriptions(object: AnyObject) {
29+
return {
30+
description: object.description,
31+
['x-gitbook-description-html']:
32+
'x-gitbook-description-html' in object
33+
? object['x-gitbook-description-html']
34+
: undefined,
35+
};
36+
}
37+
38+
/**
39+
* Resolve the first example from an object.
40+
*/
41+
export function resolveFirstExample(object: AnyObject) {
42+
if ('examples' in object && typeof object.examples === 'object' && object.examples) {
43+
const keys = Object.keys(object.examples);
44+
const firstKey = keys[0];
45+
if (firstKey && object.examples[firstKey]) {
46+
return object.examples[firstKey];
47+
}
48+
}
49+
if ('example' in object && object.example !== undefined) {
50+
return object.example;
51+
}
52+
return undefined;
53+
}
54+
55+
/**
56+
* Resolve the schema of a parameter.
57+
* Extract the description, example and deprecated from parameter.
58+
*/
59+
export function resolveParameterSchema(
60+
parameter: OpenAPIV3.ParameterBaseObject,
61+
): OpenAPIV3.SchemaObject {
62+
const schema = checkIsReference(parameter.schema) ? undefined : parameter.schema;
63+
return {
64+
// Description of the parameter is defined at the parameter level
65+
// we use display it if the schema doesn't override it
66+
...extractDescriptions(parameter),
67+
example: resolveFirstExample(parameter),
68+
// Deprecated can be defined at the parameter level
69+
deprecated: parameter.deprecated,
70+
...schema,
71+
};
72+
}
73+
74+
/**
75+
* Transform a parameter object to a property object.
76+
*/
77+
export function parameterToProperty(
78+
parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject,
79+
): {
80+
propertyName: string | undefined;
81+
schema: OpenAPIV3.SchemaObject;
82+
required: boolean | undefined;
83+
} {
84+
if (checkIsReference(parameter)) {
85+
return {
86+
propertyName: parameter.$ref ?? 'Unknown ref',
87+
schema: {},
88+
required: undefined,
89+
};
90+
}
91+
return {
92+
propertyName: parameter.name,
93+
schema: resolveParameterSchema(parameter),
94+
required: parameter.required,
95+
};
96+
}

0 commit comments

Comments
 (0)