# Fumadocs (Framework Mode, React Router): createGraphQL()
URL: /zh-TW/docs/react-router/integrations/graphql/server
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/(framework)/[framework]/integrations/graphql/server.zh-TW.mdx

GraphQL 伺服器實例。

## GraphQL 伺服器 [#graphql-server]

Fumadocs GraphQL 的主要設定。

> 請勿在瀏覽器環境中引用此設定。

### `input` [#input]

要讀取的 GraphQL schema，可以是：

* 由 SDL 檔案路徑／URL 組成的陣列。
* schema ID -&gt; 輸入的對應物件 (record) 。

物件形式的輸入可接受 SDL 檔案路徑／URL、SDL 文字、introspection 結果、`GraphQLSchema` 實例，以及回傳上述任一項的函式。

只有在此列出的 schema 才能載入，若傳入其他 ID 給 `getSchema()`，將會拋出錯誤。

```ts tab="Basic"
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: ['./schema.graphql'],
});
```

```ts tab="Record"
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: {
    // [id]：schema 輸入來源
    store: './store.graphql',
    remote: 'https://example.com/schema.graphql',
    // 也可以傳入函式，例如下載 introspection 結果
    galaxy: async () => {
      const res = await fetch('https://example.com/introspection.json');
      return res.json();
    },
  },
});
```

您可以傳入由多個 SDL 檔案組成的陣列，將它們合併為單一 schema，也支援型別擴充 (例如 `extend type Query`) 。

```ts
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: {
    api: ['./base.graphql', './orders.graphql'],
  },
});
```

### `examples` [#examples]

取自 GraphQL 文件的範例 operation，可以是檔案路徑、URL 或 GraphQL 文字。

```ts tab="Basic"
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: ['./schema.graphql'],
  examples: ['./examples.graphql'],
});
```

```ts tab="Record"
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: {
    store: './store.graphql',
    admin: './admin.graphql',
  },
  examples: {
    // [id]：對應 schema 的 GraphQL 文件
    store: ['./examples/store.graphql'],
  },
});
```

陣列會套用到所有 schema。每個具名 operation 都會成為範例，顯示在它所選取的根欄位頁面上，並取代自動產生的範例：

```graphql title="examples.graphql"
# 客戶的公開個人資料。
query CustomerProfile($id: ID! = "cus_42") {
  customer(id: $id) {
    id
    name
  }
}
```

| 範例          | 來源                                                         |
| ----------- | ---------------------------------------------------------- |
| title       | operation 名稱，例如 `CustomerProfile` 會轉為 **Customer Profile** |
| description | operation 的 `"""` 描述，或其正上方的 `#` 註解，支援 Markdown             |
| variables   | 變數的預設值 (不寫入查詢中) ，或為必要變數自動產生的值                              |
| response    | 根據選取集自動產生                                                  |

每個 operation 的名稱都必須唯一，且必須符合 schema，否則建置會失敗。

根欄位的引數必須是同名的變數，例如 `customer(id: $id)`，互動測試區才能編輯這些引數。

### `disableCache` [#disablecache]

停用已載入之 schema 與範例的快取。適合在開發期間使用，因為這些內容經常變動。

```ts
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  input: ['./schema.graphql'],
  disableCache: true,
});
```

## 只載入一次 schema [#loading-schemas-once]

頁面會透過 props 接收完整的 schema，因此每次載入頁面、切換頁面及預先擷取時，都會重新傳送一次。若 schema 較大，建議不要將其傳入：

```ts title="lib/graphql.ts"
import { createGraphQL } from '@fumadocs/graphql/server';

export const graphql = createGraphQL({
  // ID 最終會出現在 URL 中，請確保只使用 URL 安全字元
  input: { store: './store.graphql' },
  includeSchema: false, // [!code ++]
});
```

傳入 `loadSchema`，即可讓每個 schema 的 SDL 在每個瀏覽器工作階段中只載入一次。此函式也會在伺服器端算繪時執行：

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

export const GraphQLPage = createGraphQLPage({
  async loadSchema(id) {
    if (import.meta.env.SSR) {
      // 瀏覽器會在載入頁面時一併開始下載
      preload(`/api/graphql-schema/${id}`, { as: 'fetch', crossOrigin: 'anonymous' });
      const { graphql } = await import('@/lib/graphql');
      return (await graphql.getSchema(id)).sdl;
    }
    return (await fetch(`/api/graphql-schema/${id}`)).text();
  },
});
```

透過路由將 schema 提供給瀏覽器：

```ts tab="app/routes/graphql-schema.ts"
import type { Route } from './+types/graphql-schema';
import { graphql } from '@/lib/graphql';

export async function loader({ params }: Route.LoaderArgs) {
  return new Response((await graphql.getSchema(params.id)).sdl);
}
```

```ts tab="app/routes.ts"
import { route, type RouteConfig } from '@react-router/dev/routes';

export default [
  // [!code ++]
  route('api/graphql-schema/:id', 'routes/graphql-schema.ts'),
  // ...
] satisfies RouteConfig;
```

* 若使用[由 Fumadocs CLI 安裝的 UI](/docs/react-router/integrations/graphql/api-page#full-ui)，請將 `loadSchema` 傳入 `createGraphQLRenderer()`。
* 瀏覽器會保留每個 schema，直到重新載入頁面為止。若啟用 [`disableCache`](#disablecache)，請保持 `includeSchema` 開啟。

## 產生頁面 [#generating-pages]

`staticSource()` 和 `dynamicSource()` 會為您的 `loader()` 產生頁面，兩者的選項完全相同。

```ts title="lib/source.ts"
export const source = loader(
  {
    docs: docs.toFumadocsSource(),
    graphql: await graphql.staticSource({
      baseDir: 'graphql',
    }),
  },
  // ...
);
```

### `per` [#per]

自訂每個頁面涵蓋的內容，預設為 `item`。

| 模式     | 內容                                                   | 檔案路徑              |
| ------ | ---------------------------------------------------- | ----------------- |
| item   | 每個 operation，以及搭配 `includeTypes` 時的每個具名型別            | `{name}.mdx`      |
| file   | 單一 schema 的所有 operation，以及搭配 `includeTypes` 時其所有具名型別 | `{file_name}.mdx` |
| custom | 請參閱下方說明                                              | 不適用               |

設為 `custom` 時，您可以傳入函式來完全自訂產生流程：

```ts
import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  per: 'custom',
  toPages(builder) {
    builder.create({
      type: 'operation',
      path: 'my-orders.mdx',
      info: { title: 'My Orders' },
      item: { kind: 'query', name: 'orders' },
    });
  },
});
```

### `groupBy` [#groupby]

當 `per: 'item'` 時，可自訂產生的頁面要如何分組至資料夾，預設為 `kind`。

| 模式   | 資料夾                              |
| ---- | -------------------------------- |
| kind | 依種類分組，例如 `queries/`、`mutations/` |
| none | 不建立資料夾                           |

您也可以傳入一個函式，用來回傳項目的群組名稱：

```ts
import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  groupBy: (entry) => (entry.type === 'operation' ? 'operations' : 'types'),
});
```

### `includeOperations` &amp; `includeTypes` [#includeoperations--includetypes]

篩選要產生文件的 operation (query/mutation/subscription 欄位) 與具名型別。

* `includeOperations`：在 `per: 'item'` 時為每個 operation 各產生一個頁面，預設為 `true`。
* `includeTypes`：具名型別。在 `per: 'item'` 時各自擁有獨立頁面，在 `per: 'file'` 時則放在該檔案的頁面中，預設為 `false`。無論採用哪種方式，operation 頁面都會顯示其使用的型別。

型別頁面會顯示該型別的使用位置，並提供連結至其他型別及各個 operation。

```ts
import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  // 略過訂閱操作
  includeOperations: (kind, field) => kind !== 'subscription',
  // 為型別產生文件，但排除內部型別
  includeTypes: (type) => !type.name.startsWith('Internal'),
});
```

### `name` &amp; `slugify` [#name--slugify]

自訂所產生頁面的檔案名稱。

GraphQL 名稱本身就可以安全地用於 URL，因此預設會保留原始名稱 (包含大小寫) 。

```ts
import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  per: 'item',
  name: (entry) => entry.item.name.toLowerCase(),
});
```

`slugify` 會將群組名稱 (預設也包含項目名稱) 轉換為適用於 URL 的路徑片段。

### `meta` [#meta]

產生 `meta.json` 檔案以自訂頁面樹，預設為停用。

| `folderStyle` | 頁面樹                  |
| ------------- | -------------------- |
| folder        | 每個群組各為一個資料夾 (預設)     |
| separator     | 每個群組各以一個分隔符區隔，頁面列於其下 |

```ts
import { graphql } from '@/lib/graphql';

await graphql.staticSource({
  meta: { folderStyle: 'separator' },
});
```

## 供 LLM 使用的 Markdown [#markdown-for-llms]

`page.data.getText()` 會以 Markdown 格式回傳頁面中的項目：包括 operation 及其簽章、引數、範例和所用型別的 SDL，以及具名型別及其 SDL 和使用位置。例如在 [`docsLlms`](/docs/react-router/integrations/llms#docsllms) 中：

```ts
import { llms } from 'fumadocs-core/source';
import { source } from '@/lib/source';

export const docsLlms = llms(source, {
  renderPage: async (page) => {
    // [!code ++:3]
    if (page.type === 'graphql') {
      return `# ${page.data.title}\n\n${await page.data.getText('processed')}`;
    }

    // 以下為您原有的處理流程……
  },
});
```

## 載入器外掛 [#loader-plugin]

`loaderPlugin()` 會為頁面樹中的 GraphQL 頁面加上以下標示：

* 為每個 operation 頁面加上 `query`/`mutation`/`subscription` 徽章。
* 為已棄用的 operation 加上刪除線。

```ts title="lib/source.ts"
export const source = loader(
  // ...
  {
    baseUrl: '/docs',
    plugins: [graphql.loaderPlugin()],
  },
);
```