mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
OpenAPI: Add showResponseSchema option to show the full response schema
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-openapi': patch
|
||||
---
|
||||
|
||||
Add `showResponseSchema` option to show the full response schema
|
||||
@@ -4,11 +4,12 @@ import * as CURL from '@/requests/curl';
|
||||
import * as JS from '@/requests/javascript';
|
||||
import * as Go from '@/requests/go';
|
||||
import * as Python from '@/requests/python';
|
||||
import {
|
||||
type MethodInformation,
|
||||
import type {
|
||||
CallbackObject,
|
||||
MethodInformation,
|
||||
OperationObject,
|
||||
type RenderContext,
|
||||
type SecurityRequirementObject,
|
||||
RenderContext,
|
||||
SecurityRequirementObject,
|
||||
} from '@/types';
|
||||
import { getPreferredType, NoReference } from '@/utils/schema';
|
||||
import { getTypescriptSchema } from '@/utils/get-typescript-schema';
|
||||
@@ -50,14 +51,15 @@ export function Operation({
|
||||
path: string;
|
||||
method: MethodInformation;
|
||||
ctx: RenderContext;
|
||||
hasHead?: boolean;
|
||||
|
||||
hasHead?: boolean;
|
||||
headingLevel?: number;
|
||||
}): ReactElement {
|
||||
const body = method.requestBody;
|
||||
const security = method.security ?? ctx.document.security;
|
||||
let headNode: ReactNode = null;
|
||||
let bodyNode: ReactNode = null;
|
||||
let responseNode: ReactNode = null;
|
||||
let callbacksNode: ReactNode = null;
|
||||
|
||||
if (hasHead) {
|
||||
@@ -104,6 +106,42 @@ export function Operation({
|
||||
);
|
||||
}
|
||||
|
||||
if (method.responses && ctx.showResponseSchema) {
|
||||
responseNode = (
|
||||
<>
|
||||
{heading(headingLevel, 'Response Body', ctx)}
|
||||
|
||||
{Object.entries(method.responses).map(([status, response]) => {
|
||||
if (!response.content) return;
|
||||
|
||||
const mediaType = getPreferredType(response.content);
|
||||
if (!mediaType) return null;
|
||||
|
||||
const content = response.content[mediaType];
|
||||
if (!content.schema) return null;
|
||||
|
||||
return (
|
||||
<Fragment key={status}>
|
||||
{heading(headingLevel + 1, status, ctx)}
|
||||
<Markdown text={response.description} />
|
||||
|
||||
<Schema
|
||||
name="response"
|
||||
schema={content.schema}
|
||||
ctx={{
|
||||
render: ctx,
|
||||
writeOnly: false,
|
||||
readOnly: true,
|
||||
required: true,
|
||||
}}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const parameterGroups = new Map<string, ReactNode[]>();
|
||||
const endpoint = generateSample(path, method, ctx);
|
||||
|
||||
@@ -149,34 +187,14 @@ export function Operation({
|
||||
callbacksNode = (
|
||||
<>
|
||||
{heading(headingLevel, 'Webhooks', ctx)}
|
||||
{Object.entries(method.callbacks).map(([name, callback]) => {
|
||||
const nodes = Object.entries(callback).map(([path, pathItem]) => {
|
||||
const pathNodes = methodKeys.map((method) => {
|
||||
const operation = pathItem[method];
|
||||
if (!operation) return null;
|
||||
|
||||
return (
|
||||
<Operation
|
||||
key={method}
|
||||
type="webhook"
|
||||
hasHead
|
||||
path={path}
|
||||
headingLevel={headingLevel + 1}
|
||||
method={createMethod(
|
||||
method,
|
||||
pathItem,
|
||||
operation as NoReference<OperationObject>,
|
||||
)}
|
||||
ctx={ctx}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return <Fragment key={path}>{pathNodes}</Fragment>;
|
||||
});
|
||||
|
||||
return <Fragment key={name}>{nodes}</Fragment>;
|
||||
})}
|
||||
{Object.entries(method.callbacks).map(([name, callback]) => (
|
||||
<WebhookCallback
|
||||
key={name}
|
||||
callback={callback}
|
||||
ctx={ctx}
|
||||
headingLevel={headingLevel}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -201,6 +219,7 @@ export function Operation({
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
{responseNode}
|
||||
{callbacksNode}
|
||||
</ctx.renderer.APIInfo>
|
||||
);
|
||||
@@ -298,6 +317,41 @@ async function APIExample({
|
||||
return <renderer.APIExample>{children}</renderer.APIExample>;
|
||||
}
|
||||
|
||||
function WebhookCallback({
|
||||
callback,
|
||||
ctx,
|
||||
headingLevel,
|
||||
}: {
|
||||
callback: CallbackObject;
|
||||
ctx: RenderContext;
|
||||
headingLevel: number;
|
||||
}) {
|
||||
return Object.entries(callback).map(([path, pathItem]) => {
|
||||
const pathNodes = methodKeys.map((method) => {
|
||||
const operation = pathItem[method];
|
||||
if (!operation) return null;
|
||||
|
||||
return (
|
||||
<Operation
|
||||
key={method}
|
||||
type="webhook"
|
||||
hasHead
|
||||
path={path}
|
||||
headingLevel={headingLevel + 1}
|
||||
method={createMethod(
|
||||
method,
|
||||
pathItem,
|
||||
operation as NoReference<OperationObject>,
|
||||
)}
|
||||
ctx={ctx}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return <Fragment key={path}>{pathNodes}</Fragment>;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove duplicated labels
|
||||
*/
|
||||
@@ -334,24 +388,7 @@ function AuthSection({
|
||||
</p>
|
||||
) : null;
|
||||
|
||||
if (schema.type === 'http') {
|
||||
info.push(
|
||||
<renderer.Property
|
||||
key={id++}
|
||||
name="Authorization"
|
||||
type={prefix ? `${prefix} <token>` : '<token>'}
|
||||
required
|
||||
>
|
||||
{schema.description ? <Markdown text={schema.description} /> : null}
|
||||
<p>
|
||||
In: <code>header</code>
|
||||
{scopeElement}
|
||||
</p>
|
||||
</renderer.Property>,
|
||||
);
|
||||
}
|
||||
|
||||
if (schema.type === 'oauth2') {
|
||||
if (schema.type === 'http' || schema.type === 'oauth2') {
|
||||
info.push(
|
||||
<renderer.Property
|
||||
key={id++}
|
||||
|
||||
@@ -15,6 +15,7 @@ type ApiPageContextProps = Pick<
|
||||
| 'generateTypeScriptSchema'
|
||||
| 'generateCodeSamples'
|
||||
| 'proxyUrl'
|
||||
| 'showResponseSchema'
|
||||
>;
|
||||
|
||||
export interface ApiPageProps extends ApiPageContextProps {
|
||||
@@ -126,6 +127,7 @@ export async function getContext(
|
||||
document: document,
|
||||
dereferenceMap,
|
||||
proxyUrl: options.proxyUrl,
|
||||
showResponseSchema: options.showResponseSchema,
|
||||
renderer: {
|
||||
...createRenders(options.shikiOptions),
|
||||
...options.renderer,
|
||||
|
||||
@@ -19,6 +19,7 @@ export type ReferenceObject = V3_1.ReferenceObject;
|
||||
export type PathItemObject = V3_1.PathItemObject;
|
||||
export type TagObject = V3_1.TagObject;
|
||||
export type ServerObject = NoReference<V3_1.ServerObject>;
|
||||
export type CallbackObject = NoReference<V3_1.CallbackObject>;
|
||||
|
||||
export type MethodInformation = NoReference<OperationObject> & {
|
||||
method: string;
|
||||
@@ -70,4 +71,9 @@ export interface RenderContext {
|
||||
|
||||
shikiOptions?: Omit<CodeToHastOptionsCommon, 'lang'> &
|
||||
CodeOptionsThemes<BuiltinTheme>;
|
||||
|
||||
/**
|
||||
* Show full response schema instead of only example response & Typescript definitions
|
||||
*/
|
||||
showResponseSchema?: boolean;
|
||||
}
|
||||
|
||||
@@ -60,31 +60,4 @@ const defaultMdxComponents = {
|
||||
Callout,
|
||||
};
|
||||
|
||||
/**
|
||||
* **Server Component Only**
|
||||
*
|
||||
* Sometimes, if you directly pass a client component to MDX Components, it will throw an error
|
||||
*
|
||||
* To solve this, you can re-create the component in a server component like: `(props) => <Component {...props} />`
|
||||
*
|
||||
* This function does that for you
|
||||
*
|
||||
* @param c - MDX Components
|
||||
* @returns MDX Components with re-created client components
|
||||
* @deprecated no longer used
|
||||
*/
|
||||
export function createComponents<
|
||||
Components extends Record<string, FC<unknown>>,
|
||||
>(c: Components): Components {
|
||||
const mapped = Object.entries(c).map(([k, V]) => {
|
||||
// Client components are empty objects
|
||||
return [
|
||||
k,
|
||||
Object.keys(V).length === 0 ? (props: object) => <V {...props} /> : V,
|
||||
];
|
||||
});
|
||||
|
||||
return Object.fromEntries(mapped) as Components;
|
||||
}
|
||||
|
||||
export { defaultMdxComponents as default };
|
||||
|
||||
Reference in New Issue
Block a user