# Fumadocs (Framework Mode, TanStack Start): createGraphQLPage()
URL: /zh-TW/docs/tanstack-start/integrations/graphql/api-page
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/(framework)/[framework]/integrations/graphql/api-page.zh-TW.mdx

用於算繪 GraphQL 文件內容的元件

## 概覽 [#overview]

Fumadocs GraphQL 使用 `<GraphQLPage />` 元件來算繪頁面內容，此元件應為用戶端元件。

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  // 設定
});
```

### 互動測試區 [#playground]

設定端點後，operation 頁面會提供互動測試區：讀者可以編輯 operation、透過表單或 JSON 填入變數，再附上自己的標頭送出。

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    url: 'https://api.example.com/graphql',
    // 允許使用者編輯端點 URL（預設：true）
    allowUrlEdit: false,
    // 互動測試區請求的預設標頭
    headers: {
      'X-Client-Name': 'docs',
    },
  },
});
```

<Callout type="warn">
請勿將密鑰等機密資訊放入 `headers`，因為這些內容會傳送至瀏覽器、顯示在程式碼範例中，並依端點來源保存在瀏覽器的本機儲存空間 (local storage) 中。
</Callout>

查詢 (query) 與變更 (mutation) 會透過 HTTP POST 傳送，您可以替換其 fetcher，例如透過代理伺服器轉送請求：

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    async fetcher(request) {
      const start = performance.now();
      const res = await fetch('/api/proxy', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...request.headers },
        body: JSON.stringify({ query: request.query, variables: request.variables }),
      });

      return {
        type: 'response',
        status: res.status,
        time: performance.now() - start,
        body: await res.text(),
        contentType: res.headers.get('Content-Type') ?? '',
        // 選填，會顯示在 Headers 頁籤中
        headers: Array.from(res.headers),
      };
    },
  },
});
```

或者，您也可以使用 `render` 完全替換互動測試區的 UI，它會顯示在原本簽章列的位置：

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    render({ kind, name, operation }) {
      return <div>my playground</div>;
    },
  },
});
```

#### 訂閱 [#subscriptions]

在訂閱頁面上，互動測試區會訂閱 `subscriptionUrl`，並記錄收到的事件。預設值為將 `url` 的 scheme 改為 `ws(s)://` 後的網址。

| `subscriptionUrl`     | 協定                                          |
| --------------------- | ------------------------------------------- |
| `ws://`, `wss://`     | graphql-ws (`graphql-transport-ws`)         |
| `http://`, `https://` | GraphQL over SSE (distinct connections 模式)  |

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  playground: {
    url: 'https://api.example.com/graphql',
    // 在同一個端點上透過 SSE 使用 GraphQL（GraphQL over SSE）
    subscriptionUrl: 'https://api.example.com/graphql',
  },
});
```

<Callout title="瀏覽器限制">
瀏覽器無法設定 WebSocket 連線的標頭，因此 graphql-ws 改將標頭放在
`connection_init` 的酬載中傳送。
</Callout>

### 程式碼範例 [#code-samples]

範例請求會以 GraphQL 呈現，或以 cURL、JavaScript、Go、Python、Java、C# 和 Rust 程式碼呈現，這些程式碼會帶上 `playground.headers`，將請求傳送至 `playground.url` (未設定時會使用預留位置) 。互動測試區也會針對正在編輯的請求顯示相同的程式碼。訂閱頁面的範例僅以 GraphQL 呈現。

您可以透過 `codeUsages` 新增產生器，或移除預設的產生器：

```tsx title="components/api-page.tsx"
'use client';
import {
  createCodeUsageGeneratorRegistry,
  createGraphQLPage,
  registerDefaultCodeUsages,
} from '@fumadocs/graphql/ui';

// 若要從零開始，請省略預設項目
const codeUsages = registerDefaultCodeUsages(createCodeUsageGeneratorRegistry());

// 預設項目：curl、js、go、python、java、csharp、rust
codeUsages.remove('java');
codeUsages.add('graphql-request', {
  label: 'graphql-request',
  lang: 'js',
  generate({ url, query, variables = {}, headers }) {
    return `import { request } from 'graphql-request';

const data = await request(${JSON.stringify(url)}, ${JSON.stringify(query)}, ${JSON.stringify(variables)}, ${JSON.stringify(headers)});`;
  },
});

export const GraphQLPage = createGraphQLPage({ codeUsages });
```

### CodeUsageData

| Prop         | Type                                   | Description                                          |
| ------------ | -------------------------------------- | ---------------------------------------------------- |
| `url`        | `string`                               | the GraphQL endpoint                                 |
| `query`      | `string`                               | the GraphQL document                                 |
| `variables?` | `Record<string, unknown> \| undefined` |                                                      |
| `headers`    | `Record<string, string>`               | headers besides `Content-Type`, like `Authorization` |

### 交互連結 [#cross-linking]

[型別頁面](/docs/tanstack-start/integrations/graphql/server#includeoperations--includetypes)會自動互相連結，也會連結至 operation。Operation 頁面則會讓讀者留在原頁面，其中的型別會在結構描述 UI 中開啟。

您也可以自行解析這些連結：

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  typeLinks(name) {
    return `/docs/types/${name}`;
  },
  operationLinks(kind, name) {
    return `/docs/${kind}/${name}`;
  },
});
```

若型別或 operation 沒有獨立頁面，請回傳 `undefined`。

### 自訂版面配置 [#custom-layout]

您可以自訂 operation 頁面與型別頁面的版面配置。

<Tabs items={["Operation","Type"]}>
<Tab>
```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  content: {
    renderOperationLayout(slots) {
      return (
        <div className="flex flex-col gap-6">
          {slots.header}
          {slots.playground}
          {slots.description}
          {slots.deprecated}
          {slots.arguments}
          {slots.returns}
          {slots.example}
        </div>
      );
    },
  },
});
```

| Slot          | 算繪內容                                                     |
| ------------- | -------------------------------------------------------- |
| `header`      | 標題，僅在包含多個項目的頁面上顯示                                        |
| `playground`  | 簽章 (例如 `QUERY customer(id: ID!): Customer`) 、其指示詞以及互動測試區 |
| `description` | operation 的說明                                            |
| `deprecated`  | 棄用原因                                                     |
| `arguments`   | 引數                                                       |
| `returns`     | 回傳型別及其欄位                                                 |
| `example`     | 範例請求與回應，在寬版頁面上會顯示於 operation 旁                           |
</Tab>

<Tab>
```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  content: {
    renderTypeLayout(slots) {
      return (
        <div className="flex flex-col gap-6">
          {slots.header}
          {slots.definition}
          {slots.description}
          {slots.fields}
          {slots.values}
          {slots.usages}
          {slots.sdl}
        </div>
      );
    },
  },
});
```

| Slot          | 算繪內容                                            |
| ------------- | ----------------------------------------------- |
| `header`      | 名稱，僅在包含多個項目的頁面上顯示                               |
| `definition`  | SDL 的開頭 (例如 `type Order implements Node`) 及其指示詞 |
| `description` | 型別的說明                                           |
| `fields`      | 物件、介面與輸入物件的欄位，或聯集的成員                            |
| `values`      | 列舉的值                                            |
| `usages`      | 實作、所屬聯集，以及使用此型別的 operation 與欄位                  |
| `sdl`         | 型別的 SDL，在寬版頁面上會顯示於型別旁                           |
</Tab>
</Tabs>

### 結構描述 UI [#schema-ui]

自訂型別的算繪方式。

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  schemaUI: {
    render(options, ctx) {
      // 完全自訂的 schema 算繪器
      return <ctx.SchemaUI {...options} />;
    },
  },
});
```

### 國際化 [#internationalization]

假設您已在 UI 層級設定好[國際化](/docs/tanstack-start/internationalization)：

```tsx title="layout.shared.tsx"
import { defineI18n } from 'fumadocs-core/i18n';
import { uiTranslations } from 'fumadocs-ui/i18n';
import { graphqlTranslations } from '@fumadocs/graphql/i18n';

const i18n = defineI18n({
  languages: ['en', 'cn'],
  defaultLanguage: 'en',
});

export const translations = i18n
  .translations()
  .extend(uiTranslations())
  // [!code ++]
  .extend(graphqlTranslations())
  .add({
    cn: {
      displayName: 'Chinese',
      // [!code ++]
      'Arguments(operation page)': '参数',
    },
  });
```

詳細資訊請參閱[翻譯](/docs/ui/translations)。

### 語法突顯 [#syntax-highlighting]

GraphQL 頁面會使用 Shiki 為程式碼區塊進行語法突顯，若要自訂，可以傳入[語法突顯器](/docs/headless/utils/shiki)。

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';
import { highlighter } from '@/lib/highlighter';

export const GraphQLPage = createGraphQLPage({ highlighter });
```

### 自訂元件 [#custom-components]

覆寫預設的標題、程式碼區塊及 Markdown 元件。

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';

export const GraphQLPage = createGraphQLPage({
  components: {
    Heading({ id, depth, ...props }) {
      const Tag = `h${depth}` as const;
      return <Tag id={id} {...props} />;
    },
    CodeBlock({ lang, code }) {
      return <pre data-lang={lang}>{code}</pre>;
    },
  },
});
```

## 自訂 UI [#customise-ui]

若現有選項無法滿足您的自訂需求，您可以透過 [Fumadocs CLI](/docs/cli) 將 UI 安裝到您的程式碼庫中。

### 完整 UI [#full-ui]

GraphQL 頁面的完整 UI，以[無頭式層](/docs/tanstack-start/integrations/graphql/headless)為基礎建構而成。

```npm
npx @fumadocs/cli add graphql/page
```

它會自行安裝 `<GraphQLPage />`，因此不再需要 `components/api-page.tsx`。請更新 `<GraphQLPage />` 的匯入路徑：

```tsx
import { GraphQLPage } from '@/components/api-page'; // [!code --]
import { GraphQLPage } from '@/components/graphql/page'; // [!code ++]
```

### 部件 [#parts]

只需安裝您想編輯的部件，再透過 `components` 傳回即可。`components` 中沒有互動測試區的 slot：它會由已安裝的 `graphql/operation` 算繪，您也可以從 [`playground.render`](#playground) 回傳 `<OperationPlayground />`。

| 元件                   | 內容                 |
| -------------------- | ------------------ |
| `graphql/operation`  | operation，包含其引數與範例 |
| `graphql/type-docs`  | 具名型別，包含其欄位與使用之處    |
| `graphql/schema-ui`  | 型別、引數與欄位的詳細資訊      |
| `graphql/playground` | 互動測試區              |

```tsx title="components/api-page.tsx"
'use client';
import { createGraphQLPage } from '@fumadocs/graphql/ui';
import { Operation } from '@/components/graphql/operation';
import { TypeDocs } from '@/components/graphql/type-docs';

export const GraphQLPage = createGraphQLPage({
  components: {
    Operation,
    TypeDocs,
  },
});
```