# Fumadocs (Framework Mode, TanStack Start): createGraphQL()
URL: /zh-TW/docs/tanstack-start/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 ++]
});
```

TanStack Start 的路由載入器會同時在伺服器與瀏覽器上執行，因此您的文件路由不需要 `loadSchema` 也能載入 schema。只有在瀏覽器尚未取得 schema 時，才需要呼叫 server function：

```tsx title="src/routes/docs/$.tsx"
import { createServerFn } from '@tanstack/react-start';
import { graphql } from '@/lib/graphql';

// 瀏覽器已載入的 schema
const schemas = new Map<string, string>();

const getSchema = createServerFn({ method: 'GET' })
  .validator((id: string) => id)
  .handler(async ({ data: id }) => (await graphql.getSchema(id)).sdl);

export const Route = createFileRoute('/docs/$')({
  component: Page,
  loader: async ({ params }) => {
    const data = await serverLoader({ data: params._splat?.split('/') ?? [] });
    if (data.type === 'graphql') {
      const { schema: id, payload } = data.props;
      payload.sdl = schemas.get(id) ?? (await getSchema({ data: id }));
    }
    return data;
  },
});

function Page() {
  const page = useFumadocsLoader(Route.useLoaderData());
  // 第一個頁面的 schema 也要記錄
  if (page.type === 'graphql' && typeof window !== 'undefined')
    schemas.set(page.props.schema, page.props.payload.sdl!);
  // ...
}
```

* 瀏覽器會保留每個 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/tanstack-start/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()],
  },
);
```