Headless
The state and logic of API pages, without UI.
Overview
Everything outside fumadocs-openapi/ui is headless.
| Path | Module |
|---|---|
fumadocs-openapi | the page: the document, its servers and your components |
fumadocs-openapi/operation | an operation: its details, example requests and code usages |
fumadocs-openapi/playground | the auth state and the fetcher of the playground |
fumadocs-openapi/requests | encoding the data of an example into a real request |
fumadocs-openapi/requests/generators | turning that request into code usages |
Page
createOpenAPIRenderer() takes your components and returns <OpenAPIPage />, which accepts the props of generated pages.
'use client';
import { type CodeBlockProps, createOpenAPIRenderer } from 'fumadocs-openapi';
import { Operation } from '@/components/my-operation';
import { SchemaUI } from '@/components/my-schema';
export const OpenAPIPage = createOpenAPIRenderer({
components: {
Operation,
SchemaUI,
CodeBlock({ lang, code }: CodeBlockProps) {
return (
<pre>
<code className={`language-${lang}`}>{code}</code>
</pre>
);
},
},
});| Component | Renders |
|---|---|
Operation | each operation and webhook, see Operation |
SchemaUI | the JSON schemas of parameters, bodies and responses, see Schema UI |
Layout | optional, wraps the rendered operations and webhooks |
Hooks
Components under the page read its state.
| Hook | Returns |
|---|---|
useOpenAPI() | the dereferenced document (doc) and request options |
useComponents() | the components passed to the page |
useServer() | the selected server and its variables |
useTypeScriptDefinitions(schema, options) | TypeScript definitions of a JSON schema |
useRenderContext() | the render options of the page, like playground |
Operation
<OperationProvider /> derives the details of an operation or webhook, and holds its selected example request.
'use client';
import {
OperationProvider,
type PageOperationProps,
useCodeUsage,
useOperation,
useResponseExamples,
} from 'fumadocs-openapi/operation';
export function Operation(props: PageOperationProps) {
return (
<OperationProvider {...props}>
<Content />
</OperationProvider>
);
}
function Content() {
const { title, parameters, codeUsages } = useOperation();
const responses = useResponseExamples();
return (
<>
<h2>{title}</h2>
{parameters.map(({ in: location, items }) => (
<section key={location}>{items.map((param) => param.name).join(', ')}</section>
))}
{Array.from(codeUsages.map().keys(), (id) => (
<CodeUsage key={id} id={id} />
))}
{responses.map((tab) => (
<pre key={tab.code}>{JSON.stringify(tab.examples?.[0]?.sample)}</pre>
))}
</>
);
}
function CodeUsage({ id }: { id: string }) {
const code = useCodeUsage(id);
return code && <pre>{code}</pre>;
}| Hook | Returns |
|---|---|
useOperation() | the operation with its details resolved |
useExampleRequests() | the example requests, the selected one, select() and update() to edit its data |
useExampleRequest() | data of the selected example, following its updates |
useCodeUsage(id) | the code generated by codeUsages for the selected example |
useResponseExamples() | responses with example values of their preferred media type |
Prop
Type
Schema UI
generateSchemaUI() flattens a JSON schema: every $ref it reaches becomes an entry in refs, so your UI walks a map from $root instead of recursing.
'use client';
import { useMemo } from 'react';
import { generateSchemaUI } from '@fumadocs/json-schema/react';
import type { OpenAPIComponents } from 'fumadocs-openapi';
export const SchemaUI: OpenAPIComponents['SchemaUI'] = ({ client, ...options }) => {
const { $root, refs } = useMemo(() => generateSchemaUI(options), [options.root]);
const schema = refs[$root];
if (schema.type !== 'object') return null;
return (
<ul>
{schema.props.map((prop) => (
<li key={prop.name}>
{prop.name}: {refs[prop.$type].typeName}
</li>
))}
</ul>
);
};The page passes renderMarkdown and renderCodeblock in, so descriptions and examples render through your own components. client carries the anchor ID and name of the root, for deep links into a property.
infoTags are the labelled values an API page shows next to a field, like Format or Default. type decides how to open it further.
Prop
Type
Playground
Send a request without the built-in playground.
import { createBrowserFetcher, usePlaygroundAuth } from 'fumadocs-openapi/playground';
import { encodeRequestData } from 'fumadocs-openapi/requests';| Export | Does |
|---|---|
usePlaygroundAuth() | the auth state of the page, its token store and the state of a flow |
createBrowserFetcher() | sends a request from the browser, through proxyUrl when set |
encodeRequestData() | turns the data of an example into a body, headers and query |
resolveMediaAdapter() | the adapter of a media type, isMediaTypeSupported() checks it first |
How is this guide?
Last updated on
