ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

Fumadocs GraphQL:从 GraphQL Schema 一键生成带交互式 Playground 的 API 参考文档 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 SchemaSDL 文件、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 视图与 Playgroundfumadocs/graphql/css/*预设样式fumadocs/graphql根入口重导出executeGraphQL、页面构建相关类型等通用内容。安装命令与 README 一致注意graphql是 peer dependency需要自行安装且要求graphql^17.0.0及以上同时 peer 依赖fumadocs-core/fumadocs-ui^16.15.0、React 19npm i fumadocs/graphql graphql包本身还依赖fumadocs/api-docs复用其 Schema 视图/类型注解等能力、shiki代码高亮、github-slugger等这些会在构建时自动安装无需手动处理。二、服务端接入创建 GraphQL 服务实例先在lib/graphql.ts中用 createGraphQL 创建服务端实例。input支持两种形态字符串数组一组 SDL 文件路径或 URLSchema 记录recordschema id - input的映射适合多 Schema 场景。// lib/graphql.ts import { createGraphQL } from fumadocs/graphql/server; export const graphql createGraphQL({ input: [./schema.graphql], });从源码看server/index.tsxcreateGraphQL还接受disableCache选项默认false即开启内部Map缓存同一个 schema id 的加载结果PromiseLoadedSchema会被缓存避免重复解析若 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 结果JSONIntrospectionQuery或{ data: IntrospectionQuery }结构通过buildClientSchema还原为可执行的GraphQLSchemaGraphQLSchema实例代码中已构建好的 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 wont 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.tsxstaticSource()构建时一次性生成静态页面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.json的pages数组记录相对路径separator分组渲染为分隔符---标题---加展开项...相对路径适用于想用分隔线而非文件夹组织导航的布局。每个meta.json会带上所属分组的title与description。四、页面预设Page PresetsstaticSource()/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 中的 KindGroupsnone则全部平铺也可以传函数按返回值自定义分组目录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 的所有操作与类型类型为page的items数组。页面名称取自 Schema 文件名远程输入则回退为index或Overview可用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.tsxif (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.sdlSchema 的 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-darkcomponents覆盖内部渲染组件Heading、CodeBlock、Markdowncontent布局插槽——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: stringGraphQL 端点地址操作通过 HTTP POST 发送。默认请求头为Content-Type: application/json与Accept: application/graphql-responsejson, application/json请求体为{ query, variables }见 fetcher.tsfetcher?: (request, ctx) PromisePlaygroundResult替换默认 fetcher例如通过代理转发请求、附加鉴权等render?: (context) ReactNode完全替换 Playground UI。另外还有allowUrlEdit默认true允许用户编辑端点 URL关闭后以纯文本渲染与headers默认请求头作为端点无已存 header 时的初始行。PlaygroundRequest包含url、query、variables、headersPlaygroundResult区分response含status、耗时time、body、contentType与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传入客户端。如果你有特殊的分组或命名需求可以用createGraphQLPage的typeLinks/operationLinks回调覆盖默认链接解析逻辑。七、完整示例examples/graphql仓库提供了开箱即用的完整示例 examples/graphql可作为最佳实践模板Schemaexamples/graphql/schema.graphql服务端实例examples/graphql/lib/graphql.ts内容源接入examples/graphql/lib/source.tsbaseDir: (graphql)meta: true与上文一致页面渲染分支examples/graphql/app/docs/[[...slug]]/page.tsxPlayground 端点examples/graphql/app/api/graphql/route.ts。值得一提的是示例中的 Playground API 路由它是一个返回示例数据的 mock GraphQL 端点route.ts演示了如何为 Playground 提供可联调的端到端体验。该实现包含三项值得参考的工程实践请求体大小限制MaxBodySize 100 * 1024超过返回 413查询深度限制自定义depthLimit(15)校验规则防止深层嵌套文档耗尽执行资源示例值 fieldResolver对真实 Schema 执行execute()通过自定义 resolver 为各类型返回示例值如ID-1、String-string、枚举取首个值、列表返回单元素数组等使文档中的示例查询能立即得到可视化响应。将真实 GraphQL 服务器接入时只需把playground.url指向实际端点或保留/api/graphql路由并把内部实现替换为对上游服务器的代理转发。八、从源码看工作流程把以上内容串起来fumadocs/graphql的完整工作流程如下加载 SchemacreateGraphQL({ input })注册输入源loadSchema依据输入形态SDL/URL/introspection/GraphQLSchema构建GraphQLSchema并生成 SDL 文本同时进行缓存与校验生成页面树staticSource()/dynamicSource()调用schemaToPages按per预设把 Schema 转为OperationOutput/TypeOutput/PageOutput/OutputGroup组成的输出树每个节点附带path、标题、描述、弃用状态等元信息产出虚拟文件getVirtualFiles把输出树映射为虚拟.mdx页面可选自动生成meta.json并为每页注入getGraphQLPageProps()、getSchema()、toc、structuredData、_graphql元数据链接预生成页面树配置完成后generateLinks扫描全部_graphql页面产出{ types, operations }链接表随payload.links下发页面树增强loaderPlugin()在页面树中为弃用项加删除线、为操作项加类型徽标客户端渲染createGraphQLPage用 SDL 在客户端重建 Schema通过Operation/TypeDocs/ Schema 视图渲染并依据payload.links生成类型与操作间的交叉链接操作页上的 Playground 通过url/fetcher/render三种方式接入端点并执行查询。九、总结fumadocs/graphql把「Schema 解析 → 文档页面生成 → 侧边栏导航 → 交互式 Playground → 类型间交叉链接」整条链路封装在一个包内服务端用createGraphQLstaticSource/dynamicSource生成虚拟页面客户端用createGraphQLPage渲染配套preset.css与loaderPlugin()完成样式与导航增强。无论是快速为单个 Schema 生成完整 API 参考还是通过per: custom与各类渲染插槽构建高度定制化的文档体验都能在保留 Fumadocs 原生文档能力TOC、全文搜索、MDX 混排的前提下直接获得。进一步探索的仓库路径服务端实现packages/graphql/src/server/index.tsx页面生成逻辑packages/graphql/src/utils/pages.tsSchema 加载packages/graphql/src/utils/load-schema.ts客户端 UIpackages/graphql/src/ui/index.tsxPlayground fetcherpackages/graphql/src/playground/fetcher.ts完整示例examples/graphql【免费下载链接】fumadocsThe beautiful flexible React.js docs framework.项目地址: https://gitcode.com/GitHub_Trending/fu/fumadocs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进