createOpenAPI()
OpenAPI 伺服器實例。
OpenAPI 伺服器
Fumadocs OpenAPI 的主要設定。
請勿在瀏覽器環境中引用此設定。
input
要讀取的 OpenAPI schema。
- 檔案路徑
- 外部 URL
- 函式 (見下文)
只有列在此處的 schema 才能載入;若傳入 getSchema() 或由頁面預先載入的是其他 ID,則會拋出錯誤。
請勿將不受信任的 schema 傳入 input,因為其中的 $ref 可以讀取本機檔案並擷取 URL,私有主機也包含在內。
import { createOpenAPI } from 'fumadocs-openapi/server';
export const openapi = createOpenAPI({
input: ['./unkey.json'],
});只載入一次文件
頁面會透過 props 接收完整的文件,因此每次載入頁面、切換頁面與預先擷取時,都會重新傳送整份文件。若文件較大,建議將其排除:
import { createOpenAPI } from 'fumadocs-openapi/server';
export const openapi = createOpenAPI({
// ID 最後會出現在 URL 中,請確保可安全用於 URL
input: { museum: './museum.yaml' },
includeDocument: false,
});TanStack Start 的路由載入器會同時在伺服器與瀏覽器上執行,因此您的文件路由不需要 loadDocument 就能載入文件。只有在瀏覽器尚未取得文件時,才需要呼叫 server function:
import { createServerFn } from '@tanstack/react-start';
import type { Document } from 'fumadocs-openapi';
import { openapi } from '@/lib/openapi';
// 瀏覽器已載入的文件
const documents = new Map<string, Document>();
const getDocument = createServerFn({ method: 'GET' })
.validator((id: string) => id)
.handler(async ({ data: id }) => (await openapi.getSchema(id)).bundled);
export const Route = createFileRoute('/docs/$')({
component: Page,
loader: async ({ params }) => {
const data = await serverLoader({ data: params._splat?.split('/') ?? [] });
if (data.type === 'openapi') {
const { document: id, payload } = data.props;
payload.bundled = documents.get(id) ?? (await getDocument({ data: id }));
}
return data;
},
});
function Page() {
const page = useFumadocsLoader(Route.useLoaderData());
// 第一個頁面的文件也一併記錄
if (page.type === 'openapi' && typeof window !== 'undefined')
documents.set(page.props.document, page.props.payload.bundled!);
// ...
}- 若使用產生的 MDX 檔案,請改將文件放入
preloaded.docs。 - 瀏覽器會保留每份文件,直到重新載入頁面為止。使用
disableCache時,請保持啟用includeDocument。
建立代理伺服器
代理伺服器傳送 HTTP 請求時不受瀏覽器的 CORS 限制。API 互動測試區會在以下情況使用它:
- 請求未透過 CORS 允許您的來源的 API 端點。
- 機密用戶端 (具有 client secret) 的 OAuth 請求,以及裝置授權流程。
代理伺服器是公開的,無須驗證即可存取。它會轉送請求的標頭與 body,包括 Authorization。請使用 allowedOrigins 與 filterRequest 限制其存取。
設定
為代理伺服器建立路由處理常式:
import { openapi } from '@/lib/openapi';
import { createFileRoute } from '@tanstack/react-router';
const proxy = openapi.createProxy();
export const Route = createFileRoute('/api/proxy')({
server: {
handlers: {
// 預設處理所有方法,也可以個別指定方法(GET、POST 等)
ANY: async ({ request }) => {
return proxy.handle(request);
},
},
},
});接著在 createOpenAPI() 中設定其 URL:
import { createOpenAPI } from 'fumadocs-openapi/server';
export const openapi = createOpenAPI({
proxyUrl: '/api/proxy',
});允許的來源
代理伺服器預設會接受任何公開來源,並拒絕私有網路上的主機 (例如 localhost) ,也不會轉送您網站的 Cookie。
若要限制存取範圍,或要代理私有 API,請在代理伺服器路由中列出允許的來源:
openapi.createProxy({
// 字串或正規表示式
allowedOrigins: ['https://api.example.com', 'http://localhost:8080'],
});重新導向也會依照相同的規則進行檢查。
封鎖私有網路的功能需要 Node.js 或 Deno。若使用其他執行階段 (例如 Bun) ,請指定
allowedOrigins。
您可以使用 filterRequest 拒絕請求,例如只允許讀取操作:
openapi.createProxy({
// 回傳 false 的代理請求會被拒絕
filterRequest: (request) => request.method === 'GET',
});OAuth 重新導向
OAuth 提供者只接受已註冊的重新導向 URI,但 API 互動測試區預設會重新導向至目前頁面。 請建立一個路由處理常式,作為所有頁面共用的重新導向 URI。它會將使用者導回發起流程的頁面。
import { openapi } from '@/lib/openapi';
import { createFileRoute } from '@tanstack/react-router';
const handler = openapi.createOAuthHandler();
export const Route = createFileRoute('/api/oauth')({
server: {
handlers: {
GET: async ({ request }) => handler(request),
},
},
});請將此路由的 URL 傳入 createOpenAPIPage(),並在 OAuth 提供者中註冊完整 URL (例如 https://docs.example.com/api/oauth) :
export const OpenAPIPage = createOpenAPIPage({
oauthRedirectUrl: '/api/oauth',
});內容安全政策(Content Security Policy)
處理常式會透過其自身路由提供的指令碼將使用者導回。若該路由受 Content Security Policy 規範,該政策必須允許 'self' 指令碼。使用 'strict-dynamic' 的政策會忽略 'self',因此請改為將該路由排除在這類政策之外。
靜態網站
在靜態網站中,路由會預先算繪為檔案。請傳入 inline: true 將指令碼內嵌於頁面中,並讓路徑以 .html 結尾,讓靜態主機將該檔案視為 HTML 提供。
import { openapi } from '@/lib/openapi';
import { createFileRoute } from '@tanstack/react-router';
const handler = openapi.createOAuthHandler({ inline: true });
export const Route = createFileRoute('/api/oauth.html')({
server: {
handlers: {
GET: async ({ request }) => handler(request),
},
},
});請使用 .html URL 作為重新導向 URI,例如 oauthRedirectUrl: '/api/oauth.html'。由於指令碼內嵌於頁面中,套用於此路由的內容安全政策 (Content Security Policy) 必須允許內嵌指令碼。
How is this guide?
最後更新於
