@gitbook/react-openapi 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/OpenAPICodeSample.jsx +7 -4
  3. package/dist/OpenAPIDisclosure.d.ts +1 -0
  4. package/dist/OpenAPIDisclosure.jsx +6 -3
  5. package/dist/OpenAPIDisclosureGroup.jsx +16 -15
  6. package/dist/OpenAPIRequestBody.jsx +7 -2
  7. package/dist/OpenAPIRequestBodyHeaderType.d.ts +8 -0
  8. package/dist/OpenAPIRequestBodyHeaderType.jsx +25 -0
  9. package/dist/OpenAPIResponse.d.ts +1 -1
  10. package/dist/OpenAPIResponse.jsx +20 -4
  11. package/dist/OpenAPIResponseExample.jsx +15 -3
  12. package/dist/OpenAPIResponses.jsx +6 -1
  13. package/dist/OpenAPISchema.d.ts +9 -2
  14. package/dist/OpenAPISchema.jsx +87 -91
  15. package/dist/OpenAPISchemaName.d.ts +1 -1
  16. package/dist/OpenAPISchemaName.jsx +5 -5
  17. package/dist/OpenAPISecurities.jsx +59 -1
  18. package/dist/OpenAPISelect.jsx +1 -0
  19. package/dist/OpenAPISpec.jsx +16 -1
  20. package/dist/OpenAPIWebhookExample.jsx +1 -1
  21. package/dist/StaticSection.jsx +1 -1
  22. package/dist/code-samples.js +6 -3
  23. package/dist/generateSchemaExample.js +19 -14
  24. package/dist/getDisclosureLabel.d.ts +7 -0
  25. package/dist/getDisclosureLabel.js +18 -0
  26. package/dist/schemas/OpenAPISchemaItem.d.ts +7 -0
  27. package/dist/schemas/OpenAPISchemaItem.jsx +16 -0
  28. package/dist/schemas/OpenAPISchemas.jsx +3 -9
  29. package/dist/translations/de.d.ts +7 -1
  30. package/dist/translations/de.js +10 -4
  31. package/dist/translations/en.d.ts +7 -1
  32. package/dist/translations/en.js +9 -3
  33. package/dist/translations/es.d.ts +7 -1
  34. package/dist/translations/es.js +10 -4
  35. package/dist/translations/fr.d.ts +7 -1
  36. package/dist/translations/fr.js +11 -5
  37. package/dist/translations/index.d.ts +63 -9
  38. package/dist/translations/ja.d.ts +7 -1
  39. package/dist/translations/ja.js +9 -3
  40. package/dist/translations/nl.d.ts +7 -1
  41. package/dist/translations/nl.js +9 -3
  42. package/dist/translations/no.d.ts +7 -1
  43. package/dist/translations/no.js +10 -4
  44. package/dist/translations/pt-br.d.ts +7 -1
  45. package/dist/translations/pt-br.js +10 -4
  46. package/dist/translations/zh.d.ts +7 -1
  47. package/dist/translations/zh.js +10 -4
  48. package/dist/tsconfig.build.tsbuildinfo +1 -1
  49. package/dist/utils.d.ts +1 -0
  50. package/dist/utils.js +38 -0
  51. package/package.json +2 -2
  52. package/src/OpenAPICodeSample.tsx +7 -6
  53. package/src/OpenAPIDisclosure.tsx +7 -3
  54. package/src/OpenAPIDisclosureGroup.tsx +49 -48
  55. package/src/OpenAPIRequestBody.tsx +11 -2
  56. package/src/OpenAPIRequestBodyHeaderType.tsx +36 -0
  57. package/src/OpenAPIResponse.tsx +37 -5
  58. package/src/OpenAPIResponseExample.tsx +46 -35
  59. package/src/OpenAPIResponses.tsx +4 -4
  60. package/src/OpenAPISchema.tsx +157 -130
  61. package/src/OpenAPISchemaName.tsx +10 -8
  62. package/src/OpenAPISecurities.tsx +111 -7
  63. package/src/OpenAPISelect.tsx +1 -1
  64. package/src/OpenAPISpec.tsx +21 -1
  65. package/src/OpenAPIWebhookExample.tsx +2 -2
  66. package/src/StaticSection.tsx +1 -1
  67. package/src/code-samples.test.ts +3 -2
  68. package/src/code-samples.ts +19 -12
  69. package/src/generateSchemaExample.test.ts +20 -0
  70. package/src/generateSchemaExample.ts +9 -1
  71. package/src/getDisclosureLabel.ts +25 -0
  72. package/src/schemas/OpenAPISchemaItem.tsx +34 -0
  73. package/src/schemas/OpenAPISchemas.tsx +7 -13
  74. package/src/translations/de.ts +10 -4
  75. package/src/translations/en.ts +9 -3
  76. package/src/translations/es.ts +10 -4
  77. package/src/translations/fr.ts +11 -5
  78. package/src/translations/ja.ts +9 -3
  79. package/src/translations/nl.ts +9 -3
  80. package/src/translations/no.ts +10 -4
  81. package/src/translations/pt-br.ts +10 -4
  82. package/src/translations/zh.ts +10 -4
  83. package/src/utils.ts +37 -0
package/dist/utils.d.ts CHANGED
@@ -47,3 +47,4 @@ export declare function getStatusCodeClassName(statusCode: number | string): str
47
47
  * 4xx, 5xx: Error
48
48
  */
49
49
  export declare function getStatusCodeDefaultLabel(statusCode: number | string, context: OpenAPIUniversalContext): string;
50
+ export declare function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string;
package/dist/utils.js CHANGED
@@ -184,3 +184,41 @@ function getStatusCodeCategory(statusCode) {
184
184
  var category = Math.floor(code / 100);
185
185
  return category;
186
186
  }
187
+ export function getSchemaTitle(schema) {
188
+ var _a;
189
+ // Otherwise try to infer a nice title
190
+ var type = 'any';
191
+ if (schema.enum || schema['x-enumDescriptions'] || schema['x-gitbook-enum']) {
192
+ type = "".concat(schema.type, " \u00B7 enum");
193
+ // check array AND schema.items as this is sometimes null despite what the type indicates
194
+ }
195
+ else if (schema.type === 'array' && !!schema.items) {
196
+ type = "".concat(getSchemaTitle(schema.items), "[]");
197
+ }
198
+ else if (Array.isArray(schema.type)) {
199
+ type = schema.type.join(' | ');
200
+ }
201
+ else if (schema.type || schema.properties) {
202
+ type = (_a = schema.type) !== null && _a !== void 0 ? _a : 'object';
203
+ if (schema.format) {
204
+ type += " \u00B7 ".concat(schema.format);
205
+ }
206
+ // Only add the title if it's an object (no need for the title of a string, number, etc.)
207
+ if (type === 'object' && schema.title) {
208
+ type += " \u00B7 ".concat(schema.title.replaceAll(' ', ''));
209
+ }
210
+ }
211
+ if ('anyOf' in schema) {
212
+ type = 'any of';
213
+ }
214
+ else if ('oneOf' in schema) {
215
+ type = 'one of';
216
+ }
217
+ else if ('allOf' in schema) {
218
+ type = 'all of';
219
+ }
220
+ else if ('not' in schema) {
221
+ type = 'not';
222
+ }
223
+ return type;
224
+ }
package/package.json CHANGED
@@ -8,11 +8,11 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.2.1",
11
+ "version": "1.3.1",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
14
  "@gitbook/openapi-parser": "workspace:*",
15
- "@scalar/api-client-react": "^1.2.19",
15
+ "@scalar/api-client-react": "^1.3.16",
16
16
  "@scalar/oas-utils": "^0.2.130",
17
17
  "clsx": "^2.1.1",
18
18
  "flatted": "^3.2.9",
@@ -253,15 +253,11 @@ function getCustomCodeSamples(props: {
253
253
  if (customSamples && Array.isArray(customSamples)) {
254
254
  customCodeSamples = customSamples
255
255
  .filter((sample) => {
256
- return (
257
- typeof sample.label === 'string' &&
258
- typeof sample.source === 'string' &&
259
- typeof sample.lang === 'string'
260
- );
256
+ return typeof sample.source === 'string' && typeof sample.lang === 'string';
261
257
  })
262
258
  .map((sample, index) => ({
263
259
  key: `custom-sample-${sample.lang}-${index}`,
264
- label: sample.label,
260
+ label: sample.label || sample.lang,
265
261
  body: context.renderCodeBlock({
266
262
  code: sample.source,
267
263
  syntax: sample.lang,
@@ -312,6 +308,11 @@ function getSecurityHeaders(securities: OpenAPIOperationData['securities']): {
312
308
  [name]: 'YOUR_API_KEY',
313
309
  };
314
310
  }
311
+ case 'oauth2': {
312
+ return {
313
+ Authorization: 'Bearer YOUR_OAUTH2_TOKEN',
314
+ };
315
+ }
315
316
  default: {
316
317
  return {};
317
318
  }
@@ -9,11 +9,12 @@ import { Button, Disclosure, DisclosurePanel } from 'react-aria-components';
9
9
  */
10
10
  export function OpenAPIDisclosure(props: {
11
11
  icon: React.ReactNode;
12
+ header: React.ReactNode;
12
13
  children: React.ReactNode;
13
14
  label: string | ((isExpanded: boolean) => string);
14
15
  className?: string;
15
16
  }): React.JSX.Element {
16
- const { icon, children, label, className } = props;
17
+ const { icon, header, label, children, className } = props;
17
18
  const [isExpanded, setIsExpanded] = useState(false);
18
19
 
19
20
  return (
@@ -31,8 +32,11 @@ export function OpenAPIDisclosure(props: {
31
32
  : 'none',
32
33
  })}
33
34
  >
34
- {icon}
35
- <span>{typeof label === 'function' ? label(isExpanded) : label}</span>
35
+ {header}
36
+ <div className="openapi-disclosure-trigger-label">
37
+ <span>{typeof label === 'function' ? label(isExpanded) : label}</span>
38
+ {icon}
39
+ </div>
36
40
  </Button>
37
41
  <DisclosurePanel className="openapi-disclosure-panel">
38
42
  {isExpanded ? children : null}
@@ -76,7 +76,7 @@ function DisclosureItem(props: {
76
76
  });
77
77
 
78
78
  const panelRef = useRef<HTMLDivElement | null>(null);
79
- const triggerRef = useRef<HTMLButtonElement | null>(null);
79
+ const triggerRef = useRef<HTMLDivElement | null>(null);
80
80
  const isDisabled = groupState?.isDisabled || !group.tabs?.length || false;
81
81
  const { buttonProps: triggerProps, panelProps } = useDisclosure(
82
82
  {
@@ -96,55 +96,56 @@ function DisclosureItem(props: {
96
96
 
97
97
  return (
98
98
  <div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
99
- <div className="openapi-disclosure-group-header">
100
- <button
101
- slot="trigger"
102
- ref={triggerRef}
103
- {...mergeProps(buttonProps, focusProps)}
104
- disabled={isDisabled}
105
- style={{
106
- outline: isFocusVisible
107
- ? '2px solid rgb(var(--primary-color-500)/0.4)'
108
- : 'none',
109
- }}
110
- className="openapi-disclosure-group-trigger"
111
- >
112
- <div className="openapi-disclosure-group-icon">
113
- {icon || (
114
- <svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
115
- <path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
116
- </svg>
117
- )}
118
- </div>
99
+ <div
100
+ slot="trigger"
101
+ ref={triggerRef}
102
+ {...mergeProps(buttonProps, focusProps)}
103
+ aria-disabled={isDisabled}
104
+ style={{
105
+ outline: isFocusVisible
106
+ ? '2px solid rgb(var(--primary-color-500)/0.4)'
107
+ : 'none',
108
+ }}
109
+ className="openapi-disclosure-group-trigger"
110
+ >
111
+ <div className="openapi-disclosure-group-icon">
112
+ {icon || (
113
+ <svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
114
+ <path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
115
+ </svg>
116
+ )}
117
+ </div>
119
118
 
119
+ <div className="openapi-disclosure-group-label">
120
120
  {group.label}
121
- </button>
122
- {group.tabs ? (
123
- <div
124
- className="openapi-disclosure-group-mediatype"
125
- onClick={(e) => e.stopPropagation()}
126
- >
127
- {group.tabs?.length > 1 ? (
128
- <OpenAPISelect
129
- icon={selectIcon}
130
- stateKey={selectStateKey}
131
- onSelectionChange={() => {
132
- state.expand();
133
- }}
134
- items={group.tabs}
135
- placement="bottom end"
136
- >
137
- {group.tabs.map((tab) => (
138
- <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
139
- {tab.label}
140
- </OpenAPISelectItem>
141
- ))}
142
- </OpenAPISelect>
143
- ) : group.tabs[0]?.label ? (
144
- <span>{group.tabs[0].label}</span>
145
- ) : null}
146
- </div>
147
- ) : null}
121
+
122
+ {group.tabs ? (
123
+ <div
124
+ className="openapi-disclosure-group-mediatype"
125
+ onClick={(e) => e.stopPropagation()}
126
+ >
127
+ {group.tabs?.length > 1 ? (
128
+ <OpenAPISelect
129
+ icon={selectIcon}
130
+ stateKey={selectStateKey}
131
+ onSelectionChange={() => {
132
+ state.expand();
133
+ }}
134
+ items={group.tabs}
135
+ placement="bottom end"
136
+ >
137
+ {group.tabs.map((tab) => (
138
+ <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
139
+ {tab.label}
140
+ </OpenAPISelectItem>
141
+ ))}
142
+ </OpenAPISelect>
143
+ ) : group.tabs[0]?.label ? (
144
+ <span>{group.tabs[0].label}</span>
145
+ ) : null}
146
+ </div>
147
+ ) : null}
148
+ </div>
148
149
  </div>
149
150
 
150
151
  {state.isExpanded && selectedTab && (
@@ -1,5 +1,6 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import { InteractiveSection } from './InteractiveSection';
3
+ import { OpenAPIRequestBodyHeaderType } from './OpenAPIRequestBodyHeaderType';
3
4
  import { OpenAPIRootSchema } from './OpenAPISchemaServer';
4
5
  import type { OpenAPIClientContext } from './context';
5
6
  import { t } from './translate';
@@ -20,11 +21,18 @@ export function OpenAPIRequestBody(props: {
20
21
  return null;
21
22
  }
22
23
 
24
+ const stateKey = createStateKey('request-body-media-type', context.blockKey);
25
+
23
26
  return (
24
27
  <InteractiveSection
25
- header={t(context.translation, 'name' in data ? 'payload' : 'body')}
28
+ header={
29
+ <>
30
+ <span>{t(context.translation, 'name' in data ? 'payload' : 'body')}</span>
31
+ <OpenAPIRequestBodyHeaderType requestBody={requestBody} stateKey={stateKey} />
32
+ </>
33
+ }
26
34
  className="openapi-requestbody"
27
- stateKey={createStateKey('request-body-media-type', context.blockKey)}
35
+ stateKey={stateKey}
28
36
  selectIcon={context.icons.chevronDown}
29
37
  tabs={Object.entries(requestBody.content ?? {}).map(
30
38
  ([contentType, mediaTypeObject]) => {
@@ -35,6 +43,7 @@ export function OpenAPIRequestBody(props: {
35
43
  <OpenAPIRootSchema
36
44
  schema={mediaTypeObject.schema ?? {}}
37
45
  context={context}
46
+ key={contentType}
38
47
  />
39
48
  ),
40
49
  };
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
4
+ import { useSelectState } from './OpenAPISelect';
5
+ import { getSchemaTitle } from './utils';
6
+
7
+ /**
8
+ * Display the type of a request body. It only displays the type if the selected content is an array.
9
+ */
10
+ export function OpenAPIRequestBodyHeaderType(props: {
11
+ requestBody: OpenAPIV3.RequestBodyObject;
12
+ stateKey: string;
13
+ }) {
14
+ const { requestBody, stateKey } = props;
15
+ const content = requestBody.content ?? {};
16
+ const state = useSelectState(stateKey, Object.keys(content)[0]);
17
+
18
+ const selectedContentMediaType = Object.entries(content).find(
19
+ ([contentType]) => contentType === state.key
20
+ )?.[1];
21
+
22
+ // If the selected content is not an array, we don't display the type
23
+ if (
24
+ !selectedContentMediaType ||
25
+ !selectedContentMediaType.schema?.type ||
26
+ selectedContentMediaType.schema.type !== 'array'
27
+ ) {
28
+ return null;
29
+ }
30
+
31
+ return (
32
+ <span className="openapi-requestbody-header-type">
33
+ {`${getSchemaTitle(selectedContentMediaType.schema)}`}
34
+ </span>
35
+ );
36
+ }
@@ -1,7 +1,9 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
3
+ import { OpenAPISchemaPresentation } from './OpenAPISchema';
3
4
  import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
4
5
  import type { OpenAPIClientContext } from './context';
6
+ import { tString } from './translate';
5
7
  import { parameterToProperty, resolveDescription } from './utils';
6
8
 
7
9
  /**
@@ -9,14 +11,14 @@ import { parameterToProperty, resolveDescription } from './utils';
9
11
  */
10
12
  export function OpenAPIResponse(props: {
11
13
  response: OpenAPIV3.ResponseObject;
12
- mediaType: OpenAPIV3.MediaTypeObject;
14
+ mediaType: OpenAPIV3.MediaTypeObject | null;
13
15
  context: OpenAPIClientContext;
14
16
  }) {
15
17
  const { response, context, mediaType } = props;
16
18
  const headers = Object.entries(response.headers ?? {}).map(
17
19
  ([name, header]) => [name, header ?? {}] as const
18
20
  );
19
- const content = Object.entries(mediaType.schema ?? {});
21
+ const content = Object.entries(mediaType?.schema ?? {});
20
22
 
21
23
  const description = resolveDescription(response);
22
24
 
@@ -27,7 +29,31 @@ export function OpenAPIResponse(props: {
27
29
  return (
28
30
  <div className="openapi-response-body">
29
31
  {headers.length > 0 ? (
30
- <OpenAPIDisclosure icon={context.icons.plus} label="Headers">
32
+ <OpenAPIDisclosure
33
+ header={
34
+ <OpenAPISchemaPresentation
35
+ context={context}
36
+ property={{
37
+ propertyName: tString(context.translation, 'headers'),
38
+ schema: {
39
+ type: 'object',
40
+ },
41
+ required: null,
42
+ }}
43
+ />
44
+ }
45
+ icon={context.icons.plus}
46
+ label={(isExpanded) =>
47
+ tString(
48
+ context.translation,
49
+ isExpanded ? 'hide' : 'show',
50
+ tString(
51
+ context.translation,
52
+ headers.length === 1 ? 'header' : 'headers'
53
+ )
54
+ )
55
+ }
56
+ >
31
57
  <OpenAPISchemaProperties
32
58
  properties={headers.map(([name, header]) =>
33
59
  parameterToProperty({ name, ...header })
@@ -36,11 +62,17 @@ export function OpenAPIResponse(props: {
36
62
  />
37
63
  </OpenAPIDisclosure>
38
64
  ) : null}
39
- {mediaType.schema && (
65
+ {mediaType?.schema && (
40
66
  <div className="openapi-responsebody">
41
67
  <OpenAPISchemaProperties
42
68
  id={`response-${context.blockKey}`}
43
- properties={[{ schema: mediaType.schema }]}
69
+ properties={[
70
+ {
71
+ schema: mediaType.schema,
72
+ propertyName: tString(context.translation, 'response'),
73
+ required: null,
74
+ },
75
+ ]}
44
76
  context={context}
45
77
  />
46
78
  </div>
@@ -6,8 +6,8 @@ import { OpenAPIResponseExampleContent } from './OpenAPIResponseExampleContent';
6
6
  import { type OpenAPIContext, getOpenAPIClientContext } from './context';
7
7
  import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
8
8
  import { getExampleFromReference, getExamples } from './util/example';
9
- import { createStateKey, getStatusCodeDefaultLabel } from './utils';
10
- import { checkIsReference, resolveDescription } from './utils';
9
+ import { createStateKey, getStatusCodeDefaultLabel, resolveDescription } from './utils';
10
+ import { checkIsReference } from './utils';
11
11
 
12
12
  /**
13
13
  * Display an example of the response content.
@@ -41,45 +41,47 @@ export function OpenAPIResponseExample(props: {
41
41
  return Number(a) - Number(b);
42
42
  });
43
43
 
44
- const tabs = responses.map(([key, responseObject]) => {
45
- const description = resolveDescription(responseObject);
46
- const label = description ? (
47
- <Markdown source={description} />
48
- ) : (
49
- getStatusCodeDefaultLabel(key, context)
50
- );
44
+ const tabs = responses
45
+ .filter(([_, responseObject]) => responseObject && typeof responseObject === 'object')
46
+ .map(([key, responseObject]) => {
47
+ const description = resolveDescription(responseObject);
48
+ const label = description ? (
49
+ <Markdown source={description} />
50
+ ) : (
51
+ getStatusCodeDefaultLabel(key, context)
52
+ );
51
53
 
52
- if (checkIsReference(responseObject)) {
53
- return {
54
- key: key,
55
- label,
56
- statusCode: key,
57
- body: (
58
- <OpenAPIExample
59
- example={getExampleFromReference(responseObject, context)}
60
- context={context}
61
- syntax="json"
62
- />
63
- ),
64
- };
65
- }
54
+ if (checkIsReference(responseObject)) {
55
+ return {
56
+ key: key,
57
+ label,
58
+ statusCode: key,
59
+ body: (
60
+ <OpenAPIExample
61
+ example={getExampleFromReference(responseObject, context)}
62
+ context={context}
63
+ syntax="json"
64
+ />
65
+ ),
66
+ };
67
+ }
68
+
69
+ if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
70
+ return {
71
+ key: key,
72
+ label,
73
+ statusCode: key,
74
+ body: <OpenAPIEmptyExample context={context} />,
75
+ };
76
+ }
66
77
 
67
- if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
68
78
  return {
69
79
  key: key,
70
80
  label,
71
81
  statusCode: key,
72
- body: <OpenAPIEmptyExample context={context} />,
82
+ body: <OpenAPIResponse context={context} content={responseObject.content} />,
73
83
  };
74
- }
75
-
76
- return {
77
- key: key,
78
- label,
79
- statusCode: key,
80
- body: <OpenAPIResponse context={context} content={responseObject.content} />,
81
- };
82
- });
84
+ });
83
85
 
84
86
  if (tabs.length === 0) {
85
87
  return null;
@@ -97,7 +99,7 @@ export function OpenAPIResponseExample(props: {
97
99
  function OpenAPIResponse(props: {
98
100
  context: OpenAPIContext;
99
101
  content: {
100
- [media: string]: OpenAPIV3.MediaTypeObject;
102
+ [media: string]: OpenAPIV3.MediaTypeObject | null;
101
103
  };
102
104
  }) {
103
105
  const { context, content } = props;
@@ -111,6 +113,15 @@ function OpenAPIResponse(props: {
111
113
 
112
114
  const tabs = entries.map((entry) => {
113
115
  const [mediaType, mediaTypeObject] = entry;
116
+
117
+ if (!mediaTypeObject) {
118
+ return {
119
+ key: mediaType,
120
+ label: mediaType,
121
+ body: <OpenAPIEmptyExample context={context} />,
122
+ };
123
+ }
124
+
114
125
  return {
115
126
  key: mediaType,
116
127
  label: mediaType,
@@ -20,8 +20,9 @@ export function OpenAPIResponses(props: {
20
20
  }) {
21
21
  const { responses, context } = props;
22
22
 
23
- const groups = Object.entries(responses).map(
24
- ([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
23
+ const groups = Object.entries(responses)
24
+ .filter(([_, response]) => response && typeof response === 'object')
25
+ .map(([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
25
26
  const tabs = (() => {
26
27
  // If there is no content, but there are headers, we need to show the headers
27
28
  if (
@@ -83,8 +84,7 @@ export function OpenAPIResponses(props: {
83
84
  ),
84
85
  tabs,
85
86
  };
86
- }
87
- );
87
+ });
88
88
 
89
89
  const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
90
90