Display OpenAPI header description (#2857)

This commit is contained in:
Greg Bergé
2025-02-19 23:34:52 +01:00
committed by GitHub
parent bb5c6a42e7
commit a3f1fea27b
5 changed files with 93 additions and 34 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@gitbook/react-openapi': patch
---
Fix display of OpenAPI header description
+6 -12
View File
@@ -1,6 +1,6 @@
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
import { OpenAPISchemaProperties } from './OpenAPISchema';
import { resolveDescription } from './utils';
import { parameterToProperty, resolveDescription } from './utils';
import type { OpenAPIClientContext } from './types';
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
@@ -27,13 +27,11 @@ export function OpenAPIResponse(props: {
return (
<div className="openapi-response-body">
{headers.length > 0 ? (
<OpenAPIDisclosure context={context} label={'Headers'}>
<OpenAPIDisclosure context={context} label="Headers">
<OpenAPISchemaProperties
properties={headers.map(([name, header]) => ({
propertyName: name,
schema: header.schema ?? {},
required: header.required,
}))}
properties={headers.map(([name, header]) => {
return parameterToProperty({ name, ...header });
})}
context={context}
/>
</OpenAPIDisclosure>
@@ -41,11 +39,7 @@ export function OpenAPIResponse(props: {
<div className="openapi-responsebody">
<OpenAPISchemaProperties
id={`response-${context.blockKey}`}
properties={[
{
schema: mediaType.schema ?? {},
},
]}
properties={mediaType.schema ? [{ schema: mediaType.schema }] : []}
context={context}
/>
</div>
+3 -3
View File
@@ -13,8 +13,8 @@ import { OpenAPIDisclosure } from './OpenAPIDisclosure';
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
export interface OpenAPISchemaPropertyEntry {
propertyName?: string;
required?: boolean;
propertyName?: string | undefined;
required?: boolean | undefined;
schema: OpenAPIV3.SchemaObject;
}
@@ -47,7 +47,7 @@ export function OpenAPISchemaProperty(
? null
: getSchemaAlternatives(schema, new Set(circularRefs.keys()));
if ((properties && !!properties.length) || schema.type === 'object') {
if ((properties && properties.length > 0) || schema.type === 'object') {
return (
<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
<OpenAPISchemaPresentation {...props} />
+2 -17
View File
@@ -8,7 +8,7 @@ import { OpenAPIResponses } from './OpenAPIResponses';
import { OpenAPISchemaProperties } from './OpenAPISchema';
import { OpenAPISecurities } from './OpenAPISecurities';
import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
import { resolveDescription } from './utils';
import { parameterToProperty } from './utils';
/**
* Client component to render the spec for the request and response.
@@ -38,22 +38,7 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
header={group.label}
>
<OpenAPISchemaProperties
properties={group.parameters.map((parameter) => {
const description = resolveDescription(parameter);
return {
propertyName: parameter.name,
schema: {
// Description of the parameter is defined at the parameter level
// we use display it if the schema doesn't override it
description: description,
example: parameter.example,
// Deprecated can be defined at the parameter level
deprecated: parameter.deprecated,
...(parameter.schema ?? {}),
},
required: parameter.required,
};
})}
properties={group.parameters.map(parameterToProperty)}
context={context}
/>
</InteractiveSection>
+77 -2
View File
@@ -1,6 +1,8 @@
import type { AnyObject, OpenAPIV3 } from '@gitbook/openapi-parser';
import type { AnyObject, OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
export function checkIsReference(input: unknown): input is OpenAPIV3.ReferenceObject {
export function checkIsReference(
input: unknown,
): input is OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject {
return typeof input === 'object' && !!input && '$ref' in input;
}
@@ -19,3 +21,76 @@ export function resolveDescription(object: AnyObject) {
? object.description
: undefined;
}
/**
* Extract descriptions from an object.
*/
export function extractDescriptions(object: AnyObject) {
return {
description: object.description,
['x-gitbook-description-html']:
'x-gitbook-description-html' in object
? object['x-gitbook-description-html']
: undefined,
};
}
/**
* Resolve the first example from an object.
*/
export function resolveFirstExample(object: AnyObject) {
if ('examples' in object && typeof object.examples === 'object' && object.examples) {
const keys = Object.keys(object.examples);
const firstKey = keys[0];
if (firstKey && object.examples[firstKey]) {
return object.examples[firstKey];
}
}
if ('example' in object && object.example !== undefined) {
return object.example;
}
return undefined;
}
/**
* Resolve the schema of a parameter.
* Extract the description, example and deprecated from parameter.
*/
export function resolveParameterSchema(
parameter: OpenAPIV3.ParameterBaseObject,
): OpenAPIV3.SchemaObject {
const schema = checkIsReference(parameter.schema) ? undefined : parameter.schema;
return {
// Description of the parameter is defined at the parameter level
// we use display it if the schema doesn't override it
...extractDescriptions(parameter),
example: resolveFirstExample(parameter),
// Deprecated can be defined at the parameter level
deprecated: parameter.deprecated,
...schema,
};
}
/**
* Transform a parameter object to a property object.
*/
export function parameterToProperty(
parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject,
): {
propertyName: string | undefined;
schema: OpenAPIV3.SchemaObject;
required: boolean | undefined;
} {
if (checkIsReference(parameter)) {
return {
propertyName: parameter.$ref ?? 'Unknown ref',
schema: {},
required: undefined,
};
}
return {
propertyName: parameter.name,
schema: resolveParameterSchema(parameter),
required: parameter.required,
};
}