跳至內容
Fumadocs

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 接收完整的文件,因此每次載入頁面、切換頁面與預先擷取時,都會重新傳送整份文件。若文件較大,建議將其排除:

lib/openapi.ts
import { createOpenAPI } from 'fumadocs-openapi/server';

export const openapi = createOpenAPI({
  // ID 最後會出現在 URL 中,請確保可安全用於 URL
  input: { museum: './museum.yaml' },
  includeDocument: false, 
});

傳入 loadDocument,即可讓每份文件在每個瀏覽器工作階段中只載入一次。它在伺服器端算繪時也會執行:

components/api-page.tsx
'use client';
import { preload } from 'react-dom';
import { createOpenAPIPage } from 'fumadocs-openapi/ui';

export const OpenAPIPage = createOpenAPIPage({
  async loadDocument(id) {
    if (import.meta.env.SSR) {
      // 瀏覽器會在載入頁面的同時開始下載它
      preload(`/api/openapi/${id}`, { as: 'fetch', crossOrigin: 'anonymous' });
      const { openapi } = await import('@/lib/openapi');
      return (await openapi.getSchema(id)).bundled;
    }
    return (await fetch(`/api/openapi/${id}`)).json();
  },
});

透過路由將文件提供給瀏覽器:

src/pages/api/openapi/[id].ts
import type { APIRoute, GetStaticPaths } from 'astro';
import { openapi } from '@/lib/openapi';

export const prerender = true;

export const getStaticPaths = (async () => {
  return Object.keys(await openapi.getSchemas()).map((id) => ({ params: { id } }));
}) satisfies GetStaticPaths;

export const GET: APIRoute = async ({ params }) => {
  return Response.json((await openapi.getSchema(params.id!)).bundled);
};
  • loadDocument 也適用於產生的 MDX 檔案。
  • 若使用由 Fumadocs CLI 安裝的 UI,請將 loadDocument 傳入 createOpenAPIRenderer()。
  • 瀏覽器會保留每份文件,直到重新載入頁面為止。使用 disableCache 時,請保持啟用 includeDocument。

建立代理伺服器

代理伺服器傳送 HTTP 請求時不受瀏覽器的 CORS 限制。API 互動測試區會在以下情況使用它:

  • 請求未透過 CORS 允許您的來源的 API 端點。
  • 機密用戶端 (具有 client secret) 的 OAuth 請求,以及裝置授權流程。

代理伺服器是公開的,無須驗證即可存取。它會轉送請求的標頭與 body,包括 Authorization。請使用 allowedOrigins 與 filterRequest 限制其存取。

設定

為代理伺服器建立路由處理常式:

src/pages/api/proxy.ts
import type { APIRoute } from 'astro';
import { openapi } from '@/lib/openapi';

export const prerender = false;

const proxy = openapi.createProxy();

// 處理所有方法
export const ALL: APIRoute = ({ request }) => proxy.handle(request);

此路由為隨需執行,因此您的專案需要安裝轉接器。

接著在 createOpenAPI() 中設定其 URL:

lib/openapi.ts
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。它會將使用者導回發起流程的頁面。

src/pages/api/oauth.ts
import type { APIRoute } from 'astro';
import { openapi } from '@/lib/openapi';

export const prerender = false;

const handler = openapi.createOAuthHandler();

export const GET: APIRoute = ({ request }) => handler(request);

此路由採隨需執行,因此您的專案需要設定轉接器。

請將此路由的 URL 傳入 createOpenAPIPage(),並在 OAuth 提供者中註冊完整 URL (例如 https://docs.example.com/api/oauth) :

components/api-page.tsx
export const OpenAPIPage = createOpenAPIPage({
  oauthRedirectUrl: '/api/oauth', 
});

內容安全政策(Content Security Policy)

處理常式會透過其自身路由提供的指令碼將使用者導回。若該路由受 Content Security Policy 規範,該政策必須允許 'self' 指令碼。使用 'strict-dynamic' 的政策會忽略 'self',因此請改為將該路由排除在這類政策之外。

靜態網站

在靜態網站中,路由會預先算繪為檔案。請傳入 inline: true 將指令碼內嵌於頁面中,並讓路徑以 .html 結尾,讓靜態主機將該檔案視為 HTML 提供。

src/pages/api/oauth.html.ts
import type { APIRoute } from 'astro';
import { openapi } from '@/lib/openapi';

const handler = openapi.createOAuthHandler({ inline: true });

export const GET: APIRoute = ({ request }) => handler(request);

靜態建置不需要轉接器即可預先算繪此路由。

請使用 .html URL 作為重新導向 URI,例如 oauthRedirectUrl: '/api/oauth.html'。由於指令碼內嵌於頁面中,套用於此路由的內容安全政策 (Content Security Policy) 必須允許內嵌指令碼。

How is this guide?

最後更新於