跳至內容
Fumadocs

無頭式

不含 UI 的 API 頁面狀態與邏輯。

概覽

除了 fumadocs-openapi/ui 之外,其餘皆為無頭式。

路徑模組
fumadocs-openapi頁面:文件、伺服器以及您的元件
fumadocs-openapi/operationoperation:詳細資訊、範例請求與程式碼使用範例
fumadocs-openapi/playgroundAPI 互動測試區:表單、驗證與請求
fumadocs-openapi/requests將範例資料編碼為實際請求
fumadocs-openapi/requests/generators將該請求轉換為程式碼使用範例
@fumadocs/json-schema/react結構描述 UI:已針對 UI 扁平化的 JSON schema
@fumadocs/json-schema/react/client結構描述 UI 的狀態

頁面

createOpenAPIRenderer() 會接收您的元件並回傳 <OpenAPIPage />,此元件可接受所產生頁面的 props。

components/api-page.tsx
'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>
      );
    },
  },
});
元件算繪內容
Operation每個 operation 與 webhook,請參閱 Operation
SchemaUI參數、請求主體與回應的 JSON schema,請參閱 結構描述 UI
Layout選用,用來包覆已算繪的 operation 與 webhook

Hooks

頁面底下的元件可以讀取頁面的狀態。

Hook回傳值
useOpenAPI()已解除參照的文件 (doc) 與請求選項
useComponents()傳入頁面的元件
useServer()目前選取的伺服器及其變數
useTypeScriptDefinitions(schema, options)JSON schema 的 TypeScript 定義
useRenderContext()頁面的算繪選項,例如 playground

Operation

<OperationProvider /> 會推導出 operation 或 webhook 的詳細資訊,並保存目前選取的範例請求。

components/my-operation.tsx
'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回傳值
useOperation()已解析詳細資訊的 operation
useExampleRequests()範例請求、目前選取的範例,以及用來編輯其資料的 select() 和 update()
useExampleRequest()所選範例的資料,會隨其更新同步變動
useCodeUsage(id)codeUsages 為所選範例產生的程式碼
useResponseExamples()附帶偏好媒體類型範例值的回應

屬性

型別

結構描述 UI

generateSchemaUI() 會將 JSON schema 扁平化:它遇到的每個 $ref 都會成為 refs 中的一筆項目,因此您的 UI 只需從 $root 開始走訪對應表,不必遞迴處理。

<SchemaUIProvider /> 則在此基礎上管理狀態:包括從屬性開啟的 schema、聯集中已選取的成員,以及指向某個屬性的連結。

components/my-schema.tsx
'use client';
import { useMemo } from 'react';
import { generateSchemaUI } from '@fumadocs/json-schema/react';
import { SchemaUIProvider, useSchemaUI } from '@fumadocs/json-schema/react/client';
import type { OpenAPIComponents } from 'fumadocs-openapi';

export const SchemaUI: OpenAPIComponents['SchemaUI'] = ({ client, ...options }) => {
  const generated = useMemo(() => generateSchemaUI(options), [options.root]);

  return (
    <SchemaUIProvider id={client.rootId} name={client.name} generated={generated}>
      <div id={client.rootId}>
        <Schema />
      </div>
    </SchemaUIProvider>
  );
};

function Schema() {
  const { refs, path, open, back } = useSchemaUI();
  const { schema } = path[path.length - 1];

  return (
    <>
      {path.length > 1 && <button onClick={() => back(path.length - 2)}>Back</button>}
      {schema.type === 'object' && (
        <ul>
          {schema.props.map((prop) => (
            <li key={prop.name}>
              {prop.name}:{' '}
              <button onClick={() => open(prop.name, prop.$type)}>
                {refs[prop.$type].typeName}
              </button>
            </li>
          ))}
        </ul>
      )}
    </>
  );
}
useSchemaUI()說明
path已開啟的 schema,從根節點開始
open(name, $ref)、back(index)在 path 中導覽
getLink(index, name)連結至某個路徑項目屬性的 URL,造訪該 URL 會重新開啟 path
highlightedURL 所連結的最後一個路徑項目的屬性

path 的每個項目都包含要顯示的 schema,以及其 unions 和已選取的成員。對聯集呼叫 select() 即可顯示另一個成員。

頁面會傳入 renderMarkdown 與 renderCodeblock,讓說明與範例透過您自己的元件算繪。client 帶有根節點的錨點 ID 與名稱,指向屬性的連結都會以它為基準來解析。

算繪 client 的 slot

請求主體與回應會傳入 client.selector 來選取媒體類型,並傳入 client.actions 來 複製其 TypeScript 定義。

互動測試區

usePlayground() 會在 <OperationProvider /> 底下保存 API 互動測試區的狀態。表單會以所選的範例請求作為初始值,編輯內容也會同步回該範例,因此程式碼使用範例會隨之更新,並遮蔽驗證相關的值。

components/my-playground.tsx
'use client';
import { StfProvider, useFieldValue } from '@fumari/stf';
import { useOperation } from 'fumadocs-openapi/operation';
import { usePlayground } from 'fumadocs-openapi/playground';

export function MyPlayground() {
  const { parameters } = useOperation();
  const { stf, send, isSending, response } = usePlayground();

  return (
    <StfProvider value={stf}>
      {parameters.map(({ in: location, items }) =>
        items.map((param) => (
          <ParameterInput key={`${location}.${param.name}`} location={location} name={param.name} />
        )),
      )}
      <button disabled={isSending} onClick={send}>
        Send
      </button>
      {response?.result.type === 'response' && <pre>{response.result.text()}</pre>}
    </StfProvider>
  );
}

function ParameterInput({ location, name }: { location: string; name: string }) {
  const [value, setValue] = useFieldValue([location, name]);

  return (
    <input
      aria-label={name}
      value={String(value ?? '')}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}
欄位說明
stf表單 (一個 @fumari/stf 資料引擎) ,包含 path、query、header、cookie 與 body,並在 auth 中存放頁面的驗證值
body在表單中編輯的請求 body,及其偏好的媒體類型
auth所選安全性需求的驗證欄位;可用 select() 切換,authorize() 則會取得 OAuth 2.0 權杖並填入欄位
send()、isSending、response、clearResponse()將表單作為請求送出,以及上一次請求的結果

它接受 fetchOptions 來自訂請求 (例如 onRequestInit()) 、authProviders 來處理安全性方案 (請參閱授權) ,以及 transformAuthInputs 來自訂驗證欄位。

請求

usePlayground() 底層所使用的元件,可讓您不透過它直接傳送請求。

匯出用途
createBrowserFetcher()從瀏覽器傳送請求,若有設定 proxyUrl 則經由它傳送;其回應包含 duration、mediaType、fileName 與 text()
encodeRequestData()將範例的資料轉換為 body、headers 與 query,由 fumadocs-openapi/requests 匯出
resolveMediaAdapter()取得媒體類型的轉接器,不支援時為 undefined
useAuthFields()operation 的驗證欄位,以及這些欄位編碼後的請求資料
usePlaygroundAuth()頁面的驗證值位於 stf,返回該頁面的流程位於 returned
useOpenIdConnectFlows()OpenID Connect 設定中的 OAuth 2.0 流程,或探索流程時發生的 error;載入期間會暫停 (suspend)
requestOAuthToken()執行 OAuth 2.0 流程,onUserCode 會顯示使用者在裝置授權時需輸入的代碼

How is this guide?

最後更新於