Fumadocs GraphQL:从 GraphQL Schema 一键生成带交互式 Playground 的 API 参考文档
2026/9/15 13:50:05 网站建设 项目流程

Fumadocs GraphQL:从 GraphQL Schema 一键生成带交互式 Playground 的 API 参考文档

【免费下载链接】fumadocsThe beautiful & flexible React.js docs framework.项目地址: https://gitcode.com/GitHub_Trending/fu/fumadocs

导读

@fumadocs/graphql是 Fumadocs 生态中专用于 API 参考文档生成的官方包:它读取你的 GraphQL Schema(SDL 文件、introspection JSON 或GraphQLSchema实例),将其转换成一批可直接挂载到 Fumadocs 内容源(source)中的虚拟页面,并为每个 Operation 页面内置交互式 Playground,支持类型与操作间的交叉链接、弃用标记和深度的 UI 自定义。阅读本文后,你将掌握安装、服务端接入、页面生成、客户端渲染、样式引入的完整流程,并能理解per页面预设、groupBy分组、baseUrl链接预生成等核心参数背后的源码实现,从而把 GraphQL Schema 快速变成一套专业、可检索、可联调的技术文档。

一、包结构与安装

@fumadocs/graphql位于仓库的 packages/graphql 目录,当前版本0.2.6。从 package.json 的exports字段可以看到它对外暴露了四个入口,分别承担不同职责:

  • @fumadocs/graphql/server:服务端入口(dist/server/index.js),提供createGraphQL()工厂函数,负责加载 Schema 并把 Schema 转换成虚拟页面;
  • @fumadocs/graphql/ui:客户端入口(dist/ui/index.js),提供createGraphQLPage(),负责把页面数据渲染成可视化文档,包含 Schema 视图与 Playground;
  • @fumadocs/graphql/css/*:预设样式;
  • @fumadocs/graphql根入口:重导出executeGraphQL、页面构建相关类型等通用内容。

安装命令与 README 一致,注意graphql是 peer dependency,需要自行安装,且要求graphql@^17.0.0及以上(同时 peer 依赖fumadocs-core/fumadocs-ui^16.15.0、React 19):

npm i @fumadocs/graphql graphql

包本身还依赖@fumadocs/api-docs(复用其 Schema 视图/类型注解等能力)、shiki(代码高亮)、github-slugger等,这些会在构建时自动安装,无需手动处理。

二、服务端接入:创建 GraphQL 服务实例

先在lib/graphql.ts中用 createGraphQL 创建服务端实例。input支持两种形态:

  • 字符串数组:一组 SDL 文件路径或 URL;
  • Schema 记录(record)schema id -> input的映射,适合多 Schema 场景。
// lib/graphql.ts import { createGraphQL } from '@fumadocs/graphql/server'; export const graphql = createGraphQL({ input: ['./schema.graphql'], });

从源码看(server/index.tsx),createGraphQL还接受disableCache选项,默认false即开启内部Map缓存:同一个 schema id 的加载结果(Promise<LoadedSchema>)会被缓存,避免重复解析;若 Schema 会在运行时变化(如动态获取),可传入disableCache: true关闭缓存。

2.1 input 支持的四种输入形态

依据 load-schema.ts 的实现,input中每一项可以是:

输入形态说明底层处理
SDL 文件路径 / URL.graphql/.graphqls/.gql结尾的本地路径,或http(s)://远程地址;也支持字符串数组(合并为单个 Schema)读取文件或fetch远程内容后,通过buildSchemaFromSDL构建,并用validateSchema做严格校验
SDL 文本直接内联的 Schema 字符串,可包含extend type定义同上,作为 SDL 直接构建
Introspection 结果(JSON)IntrospectionQuery{ data: IntrospectionQuery }结构通过buildClientSchema还原为可执行的GraphQLSchema
GraphQLSchema实例代码中已构建好的 Schema 对象直接使用,并通过printSchema生成 SDL 文本

注意loadSchema对 SDL 输入会执行validateSchema严格校验,出错时会抛出带具体错误信息的异常;而客户端侧的buildSchemaFromSDL会跳过校验,因此服务端是 Schema 合法性的第一道关口。加载成功后返回LoadedSchema,其中sdl字段是 Schema 的 SDL 文本形式,会被传递到客户端用于重建 Schema 与渲染。

三、把生成的页面接入内容源

lib/source.ts中,把graphql.staticSource()的结果作为一个独立 source 传入loader(),并通过plugins注册loaderPlugin()

// lib/source.ts import { loader } from 'fumadocs-core/source'; import { defineDocs } from 'fumadocs-mdx/macro'; import { graphql } from './graphql'; const docs = defineDocs({ dir: 'content/docs', }); export const source = loader( { docs: docs.toFumadocsSource(), graphql: await graphql.staticSource({ // a route group, generated pages won't have a `/graphql` prefix in their URLs baseDir: '(graphql)', meta: true, }), }, { baseUrl: '/docs', plugins: [graphql.loaderPlugin()], }, );

这里的staticSource会把 Schema 展开为一组虚拟.mdx页面(与常规content/docs下的 MDX 页面共存)。从源码实现看,createGraphQL返回的服务实例提供了四种能力(server/index.tsx):

  • staticSource():构建时一次性生成静态页面;
  • dynamicSource():提供cache: 'custom'的动态源,支持按需重新生成并带invalidate()清理缓存,适合 Schema 频繁变化的场景;
  • loaderPlugin():返回页面树转换插件,负责在侧边栏/页面树中渲染弃用删除线(line-through)与 query/mutation/subscription 操作徽标;
  • getSchema(schemaId)/getSchemas():按 id 获取已加载的 Schema,供 API 路由等场景使用。

staticSource还接受baseDir(路由分组目录,例如(graphql)可让生成的页面 URL 不带/graphql前缀)与meta(是否自动生成meta.json导航元数据,见下节)。

loaderPlugin()对应的 graphqlPlugin 实现值得关注:它以enforce: 'pre'在页面树转换前执行,对带_graphql元数据的页面做两件事——若deprecated为 true 则在页面树节点名上添加删除线样式;若页面属于 query/mutation/subscription 三种操作之一,则在节点名后追加对应的KindLabel徽标。

3.1 meta.json 自动生成

meta: true时,服务端会根据页面分组结构自动生成meta.json文件(server/index.tsx)。meta选项还支持对象形式{ folderStyle: 'folder' | 'separator' }

  • folder(默认):分组以真实文件夹形式呈现,meta.jsonpages数组记录相对路径;
  • separator:分组渲染为分隔符(---标题---)加展开项(...相对路径),适用于想用分隔线而非文件夹组织导航的布局。

每个meta.json会带上所属分组的titledescription

四、页面预设(Page Presets)

staticSource()/dynamicSource()内部会把 Schema 转成页面树,这一逻辑集中在 schemaToPages。per选项决定页面的组织粒度,共三种预设:

4.1 per: 'item'(默认)

每个 Operation 或具名类型生成一页。该模式接受以下参数:

  • groupBy: 'kind' | 'none' | function:默认'kind',按类型分组到queries/mutations/subscriptions/objects/interfaces/unions/enums/inputs/scalars/九个目录(分组目录与标题的映射见 pages.ts 中的 KindGroups);'none'则全部平铺;也可以传函数,按返回值自定义分组目录;
  • includeOperations: boolean | (kind, field) => boolean:默认true,是否(以及按条件)为根类型上的每个操作字段生成页面;
  • includeTypes: boolean | (type) => boolean:默认true,是否(以及按条件)为每个具名类型生成页面;
  • name: (output) => string:自定义页面文件名;
  • slugify: (name) => string:把名称转换为 URL 安全的片段。源码注释明确说明 GraphQL 名称本身已是 URL 安全的,因此默认保留原名(含大小写),只有自定义groupBy函数的分组名会经过slugify

4.2 per: 'file'

每个 Schema 只生成一个汇总页面,页面中列出该 Schema 的所有操作与类型(类型为pageitems数组)。页面名称取自 Schema 文件名(远程输入则回退为indexOverview),可用name覆盖。

4.3 per: 'custom'

完全自建页面构建器:传入toPages(builder)回调,通过builder.create(entry)手动生成任意OutputEntry(操作页、类型页、汇总页或分组),适合需要特殊页面结构的场景。

includeOperations/includeTypes也可以传函数做精细化过滤,例如只对某类操作生成页面;页面标题方面,操作页标题由字段名生成(getOperationTitle),描述取字段/类型的descriptiondeprecated状态由deprecationReason推导。

五、客户端渲染与 UI 配置

5.1 创建 GraphQL 页面组件

在客户端组件中调用 createGraphQLPage:

// components/api-page.tsx 'use client'; import { createGraphQLPage } from '@fumadocs/graphql/ui'; export const GraphQLPage = createGraphQLPage({ playground: { url: '/api/graphql', }, });

5.2 接入文档页面

在动态路由页面中,根据page.type === 'graphql'分支渲染(README 示例为app/docs/[[...slug]]/page.tsxexamples/graphql示例中对应的路由为 examples/graphql/app/docs/[[...slug]]/page.tsx):

if (page.type === 'graphql') { return ( <DocsPage toc={page.data.toc} full> <DocsTitle>{page.data.title}</DocsTitle> <DocsDescription>{page.data.description}</DocsDescription> <DocsBody> <GraphQLPage {...page.data.getGraphQLPageProps()} /> </DocsBody> </DocsPage> ); }

getGraphQLPageProps()由服务端在生成虚拟页面时注入(server/index.tsx),返回的数据结构为GraphQLPageProps:包含payload.sdl(Schema 的 SDL 文本,客户端据此用buildSchemaFromSDL重建 Schema)与payload.links(类型/操作到页面 URL 的映射),以及items等页面渲染信息。

渲染流程上,GraphQLPage组件会构建一个RenderContext(封装 Schema、SDL、shiki、链接与各类渲染插槽),操作条目交给Operation组件、类型条目交给TypeDocs组件渲染(见 api-page.tsx)。

5.3 引入样式

在全局 CSS 中引入预设样式:

@import '@fumadocs/graphql/css/preset.css';

样式文件位于 packages/graphql/css/preset.css。

5.4 createGraphQLPage 的完整选项

CreateGraphQLPageOptions类型定义(ui/index.tsx)可看到完整的自定义能力:

  • typeLinks?: (name, ctx) => string | undefined:解析某个具名类型文档页的 URL,用于类型引用间的交叉链接;返回undefined表示该类型没有独立页面;
  • operationLinks?: (kind, name, ctx) => string | undefined:解析某个操作文档页的 URL,用于类型页上的“使用该操作的场景(usage backlinks)”反向链接;
  • playground:交互式 Playground,见下一节;
  • shiki/shikiOptions:代码高亮工厂与主题配置,默认defaultShikiFactory、浅色github-light/ 深色github-dark
  • components:覆盖内部渲染组件(HeadingCodeBlockMarkdown);
  • content:布局插槽——renderPageLayout(页面级)、renderOperationLayout(操作页:header、description、deprecated、directives、playground、arguments、returns、example 等插槽)、renderTypeLayout(类型页:header、description、directives、relations、fields、values、scalar 等插槽);
  • schemaUI.render:替换整个 Schema 视图。

六、Playground 与交叉链接

6.1 Playground 配置

playground选项控制操作页面上的交互式 Playground,支持三种配置方式:

  • url: string:GraphQL 端点地址,操作通过 HTTP POST 发送。默认请求头为Content-Type: application/jsonAccept: application/graphql-response+json, application/json,请求体为{ query, variables }(见 fetcher.ts);
  • fetcher?: (request, ctx) => Promise<PlaygroundResult>:替换默认 fetcher,例如通过代理转发请求、附加鉴权等;
  • render?: (context) => ReactNode:完全替换 Playground UI。

另外还有allowUrlEdit(默认true,允许用户编辑端点 URL,关闭后以纯文本渲染)与headers(默认请求头,作为端点无已存 header 时的初始行)。

PlaygroundRequest包含urlqueryvariablesheadersPlaygroundResult区分response(含status、耗时timebodycontentType)与client_error(含message)。默认 fetcherexecuteGraphQL同时被包根入口导出,可在服务端/客户端复用。

6.2 交叉链接的预生成

README 提到:当你在staticSource()中传入baseUrl(即loader()baseUrl,如/docs)时,类型与操作的交叉链接会被预先生成。实现上,链接生成发生在 generateLinks:遍历loader.getPages(locale)中所有带_graphql元数据的页面,把“类型名 -> 页面 URL”存入links.types,把“${kind}:${name}-> 页面 URL”存入links.operations,最终作为payload.links传入客户端。如果你有特殊的分组或命名需求,可以用createGraphQLPagetypeLinks/operationLinks回调覆盖默认链接解析逻辑。

七、完整示例:examples/graphql

仓库提供了开箱即用的完整示例 examples/graphql,可作为最佳实践模板:

  • Schema:examples/graphql/schema.graphql;
  • 服务端实例:examples/graphql/lib/graphql.ts;
  • 内容源接入:examples/graphql/lib/source.ts(baseDir: '(graphql)'+meta: true,与上文一致);
  • 页面渲染分支:examples/graphql/app/docs/[[...slug]]/page.tsx;
  • Playground 端点:examples/graphql/app/api/graphql/route.ts。

值得一提的是示例中的 Playground API 路由:它是一个返回示例数据的 mock GraphQL 端点(route.ts),演示了如何为 Playground 提供可联调的端到端体验。该实现包含三项值得参考的工程实践:

  1. 请求体大小限制MaxBodySize = 100 * 1024,超过返回 413;
  2. 查询深度限制:自定义depthLimit(15)校验规则,防止深层嵌套文档耗尽执行资源;
  3. 示例值 fieldResolver:对真实 Schema 执行execute(),通过自定义 resolver 为各类型返回示例值(如ID->'1'String->'string'、枚举取首个值、列表返回单元素数组等),使文档中的示例查询能立即得到可视化响应。

将真实 GraphQL 服务器接入时,只需把playground.url指向实际端点,或保留/api/graphql路由并把内部实现替换为对上游服务器的代理转发。

八、从源码看工作流程

把以上内容串起来,@fumadocs/graphql的完整工作流程如下:

  1. 加载 SchemacreateGraphQL({ input })注册输入源;loadSchema依据输入形态(SDL/URL/introspection/GraphQLSchema)构建GraphQLSchema并生成 SDL 文本,同时进行缓存与校验;
  2. 生成页面树staticSource()/dynamicSource()调用schemaToPages,按per预设把 Schema 转为OperationOutput/TypeOutput/PageOutput/OutputGroup组成的输出树,每个节点附带path、标题、描述、弃用状态等元信息;
  3. 产出虚拟文件getVirtualFiles把输出树映射为虚拟.mdx页面(可选自动生成meta.json),并为每页注入getGraphQLPageProps()getSchema()tocstructuredData_graphql元数据;
  4. 链接预生成:页面树配置完成后,generateLinks扫描全部_graphql页面,产出{ types, operations }链接表随payload.links下发;
  5. 页面树增强loaderPlugin()在页面树中为弃用项加删除线、为操作项加类型徽标;
  6. 客户端渲染createGraphQLPage用 SDL 在客户端重建 Schema,通过Operation/TypeDocs/ Schema 视图渲染,并依据payload.links生成类型与操作间的交叉链接;操作页上的 Playground 通过url/fetcher/render三种方式接入端点并执行查询。

九、总结

@fumadocs/graphql把「Schema 解析 → 文档页面生成 → 侧边栏导航 → 交互式 Playground → 类型间交叉链接」整条链路封装在一个包内:服务端用createGraphQL+staticSource/dynamicSource生成虚拟页面,客户端用createGraphQLPage渲染,配套preset.cssloaderPlugin()完成样式与导航增强。无论是快速为单个 Schema 生成完整 API 参考,还是通过per: 'custom'与各类渲染插槽构建高度定制化的文档体验,都能在保留 Fumadocs 原生文档能力(TOC、全文搜索、MDX 混排)的前提下直接获得。

进一步探索的仓库路径:

  • 服务端实现:packages/graphql/src/server/index.tsx
  • 页面生成逻辑:packages/graphql/src/utils/pages.ts
  • Schema 加载:packages/graphql/src/utils/load-schema.ts
  • 客户端 UI:packages/graphql/src/ui/index.tsx
  • Playground fetcher:packages/graphql/src/playground/fetcher.ts
  • 完整示例:examples/graphql

【免费下载链接】fumadocsThe beautiful & flexible React.js docs framework.项目地址: https://gitcode.com/GitHub_Trending/fu/fumadocs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询