Blume中文文档

API 参考

GraphQL 参考

从 GraphQL schema 生成原生 API 参考,每个根字段和每个具名类型各占一个页面,带参数、示例与 Try it 演练场

把一个 GraphQL schema 指给 Blume,它就会生成一份原生 API 参考:每个根字段一个真实页面 —— query、mutation 和 subscription —— 外加每个具名类型一个页面(object、input object、enum、interface、union 以及自定义标量)。每个页面都会展示参数、默认值、弃用信息和使用反向链接,并配有一段生成的示例操作、代码示例以及一个交互式 Try it 面板。由于每个页面都是一个真正的 Blume 页面,它有自己的 URL,会出现在站内搜索和 llms.txt 中,还会得到一张 Open Graph 图片 —— 与手写文档别无二致。

这份参考是 blume/reference 中的 graphql() 适配器,登记在 reference 下,与任何 OpenAPI 或 AsyncAPI 适配器并列:

import { defineConfig } from "blume";
import { graphql } from "blume/reference";

export default defineConfig({
  reference: [
    graphql({
      spec: "./schema.graphql",
      endpoint: "https://api.example.com/graphql",
    }),
  ],
});

它把参考挂在 /graphql(一个概览页)上,根字段位于 /graphql/queries/<field>、/graphql/mutations/<field> 和 /graphql/subscriptions/<field>,类型则按种类分组放在 /graphql/objects/<type>、/graphql/enums/<type> 等位置。

spec 要么是你项目中某个本地文件的路径,要么是一个 http(s) URL,并接受两种格式:

  • SDL 文本 —— 一个带类型定义的 .graphql 文件。文件用到却未声明的指令,例如 Apollo Federation 的 @key 或 AppSync 的 @aws_*,会被忽略。
  • 内省结果 —— 运行标准内省查询得到的 JSON,可以是原始的 { "__schema": … } 结构,也可以是完整的 { "data": { "__schema": … } } 响应信封。

endpoint 是 GraphQL API 的实际访问地址。schema 与 OpenAPI 文档不同,它不指明任何服务器 —— 因此 Try it 面板和生成的代码示例都以这个地址为目标。不写它的话,示例会用一个占位 URL 渲染出来,由读者自行替换。

参考不会自己添加页眉标签页。要让它露出来,把一个导航标签页指向它的路由 —— 这同时也限定了参考侧边栏的范围:

navigation: {
  tabs: [{ label: "GraphQL", path: "/graphql" }],
}

生成的示例#

每个操作页面都带有一段完整且合法的示例操作 —— 每个参数对应一个变量,类型取自 schema,返回类型上带一层有界深度的选择集 —— 外加与之匹配的示例变量,以及一份镜像同一选择集的示例响应。代码示例会以每种配置的语言展示确切的 HTTP 请求(一个发送 { query, variables } 的 JSON POST)。可选的语言与 openapi() 相同,而 codeSamples: false 则一个都不显示:

reference: [
  graphql({
    spec: "./schema.graphql",
    codeSamples: ["curl", "js"],   // openapi() 提供的任意语言
  }),
],

类型页面#

具名类型各自拥有可深链的页面,并在侧边栏中按种类分组:字段与输入字段(类型带链接)、枚举值、union 成员、interface 的实现,以及一个 Used by 小节,列出返回或接受该类型的操作,以及引用它的其它类型。规范内置的标量(String、Int……)不生成页面;自定义标量则会生成,包括它们的 specifiedBy URL。

多份 schema#

sources 中的每个条目都在自己的路由上渲染一份 schema。按来源设置的 endpoint 会覆盖适配器的:

reference: [
  graphql({
    endpoint: "https://api.example.com/graphql",
    sources: [
      { label: "Public API", spec: "./schema.graphql" },
      {
        label: "Admin API",
        route: "/graphql-admin",
        spec: "./admin.graphql",
        endpoint: "https://admin.example.com/graphql",
      },
    ],
  }),
],

spec 是单条目 sources 的简写。需要不同显示选项的 schema 应放进各自独立的 graphql() 适配器,每个配一个 route。每个来源接受与 openapi() 相同的按来源控制项:includeInSearch、includeInLlms、noindex 和 seoDescriptionSuffix(这里自动生成的那句话会点明具体的 query、mutation 或类型 —— “GraphQL API 中 pets query 的参考文档。”)。

Try it 演练场#

query 和 mutation 页面会渲染一个交互式面板:编辑请求体(query 与变量),把它指向你的 endpoint 或一个自定义 URL,然后发送 —— 代码示例会实时更新,因此你复制到的内容与实际发出的请求逐字节一致。用 playground: false 关闭它。subscription 页面则改为展示生成的操作和一个示例事件:subscription 跑在有状态的传输之上(WebSocket 或 SSE),而演练场那唯一一次 HTTP POST 说不了这种话。

如果你的 GraphQL API 不允许来自文档站点的跨域请求,发送就会走一个 CORS 代理 —— 可以是你自己的 URL,也可以是 true 表示使用内置的 /_api-proxy 端点(如果你设了 basePath,它就在其之下;它需要服务端输出:一个主机适配器,例如来自 blume/deploy 的 deployment: vercel())。内置代理只会转发到已文档化规范所声明的 origin —— 每个配置过的 GraphQL endpoint,加上已记录的 OpenAPI 规范里任何绝对的 servers[].url —— 因此一个公开的文档部署无法被指向其它主机。这也意味着 endpoint 是让代理正常工作的必需项:没有它,代理就没有可为这份参考放行的 origin,会拒绝每一次发送(构建时会就此发出警告)。请求体上限、请求头转发和响应头与 OpenAPI 代理完全相同。

reference: [
  graphql({
    spec: "./schema.graphql",
    endpoint: "https://api.example.com/graphql",
    playground: { proxy: true },
  }),
],

GraphQL 没有对应的 Scalar 版本:scalar() 嵌入页只读取 OpenAPI 和 AsyncAPI 文档,因此 GraphQL 参考始终以原生方式渲染。