# AsyncAPI 参考
Source: https://blume.ndjp.net/docs/references/asyncapi/
English: https://useblume.dev/docs/references/asyncapi

事件驱动的 API 使用 `blume/reference` 中的 `asyncapi()` 适配器，它登记在 `reference` 下，与任何 [OpenAPI](/docs/references/openapi/) 或 [GraphQL](/docs/references/graphql/) 适配器并列。它接受与 `openapi()` 相同的选项，并用同一个原生渲染器渲染。每个 `send`/`receive` 操作都会变成一个真实页面，带消息 payload 与 header 的 schema 表、channel 参数、协议绑定、一个依据规范中 `securitySchemes`（服务器级与操作级，可选项渲染成“或”字样的分组）推导出的 Authorization 小节，以及一个 [Try it](#try-it-for-events) 消息编辑器。由于每个操作都是一个真正的 Blume 页面，它有自己的 URL，会出现在**站内搜索**和 `llms.txt` 中，还会得到一张 Open Graph 图片 —— 与手写文档别无二致。

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { asyncapi } from "blume/reference";

export default defineConfig({
  reference: [asyncapi({ spec: "./asyncapi.yaml" })],
});
```

它把参考挂在 `/events`（一个概览页）上，每个操作各自占其下方的一个页面。`spec` 要么是一个 `http(s)` URL，要么是你项目中某个本地文件的路径，JSON 或 YAML 均可。与所有参考一样，它不会自己添加页眉标签页 —— 把一个[导航标签页](/docs/content/navigation/)指向它的路由，即可让它露出来，并限定操作侧边栏的范围：

```ts blume.config.ts
navigation: {
  tabs: [{ label: "Events", path: "/events" }],
}
```

## 规范版本 [#spec-versions]

AsyncAPI **2.x 规范会自动规范化到 3.x**，用的是官方 AsyncAPI 转换器，因此 `publish`/`subscribe` 的 channel 会映射到 `send`/`receive` 的操作页面上，URL 保持稳定 —— 之后若再通过该转换器升级规范文件本身，也不会挪动任何东西。这个转换器是一个可选的 peer 依赖，因此规范为 1.x 或 2.x 的站点需要安装它（`npm install @asyncapi/converter`）；不安装的话构建会失败并给出这条安装命令。3.x 规范则无需任何额外东西。操作按 tag 分组；没有 tag 的操作归在其 channel 地址之下。

## 代码示例 [#code-samples]

代码示例是**感知协议**的，依据操作的绑定（或其服务器的协议）来选：WebSocket 用 `wscat` 和一段浏览器 `WebSocket` 代码，Kafka 用 `kcat`，MQTT 用 `mosquitto_pub`/`mosquitto_sub`。`codeSamples` 按与 `openapi()` 上挑选语言相同的方式过滤这个集合，而 `codeSamples: false` 则一个都不显示。若某个协议没有受支持的工具，就只渲染消息 payload 示例，而不会编造一个客户端出来。

## 共用选项 [#shared-options]

[OpenAPI](/docs/references/openapi/) 上记录的一切都照搬过来，[`playground`](#try-it-for-events) 也不例外：[`route`](/docs/references/openapi/)、带 `label`/`route` 的 [`sources`](/docs/references/openapi/)、`expandSchemas`、那些[按来源的索引](/docs/references/openapi/)开关（`seoDescriptionSuffix` 同样可用 —— 自动生成的那句话改为点明 channel 与动作，而不是端点），以及按操作的 summary、description、tag 和 endpoint（`SEND user/signup`）建立的搜索索引。

## 改为嵌入 Scalar [#embedding-scalar-instead]

`asyncapi()` 始终渲染 Blume 自己的页面。若想改为嵌入 [Scalar](https://scalar.com) 的界面，就列出一个指向 AsyncAPI 文档的 [`scalar()`](/docs/references/scalar/) 适配器 —— 它的嵌入页会自动识别文档类型，并渲染 channel、操作、消息和一个 Models 小节。Scalar 自己没有 AsyncAPI 演练场，因此这样一换就把消息编辑器换掉了，而且按来源的控制项里也只有 `noindex` 对它适用。

## 事件的 Try it [#try-it-for-events]

原生渲染的操作页面在这里也带一个 **Try it** 面板，条件与 [OpenAPI 面板](/docs/references/openapi/)完全一致：以折叠状态在服务端渲染，其 JavaScript 只在读者首次打开时才加载。

无论协议为何，面板打开时都是一个 payload 编辑器，内容按消息的 `examples` 预填 —— 若消息没有声明任何 `examples`，则从 payload schema 中采样一个值 —— 并在你输入时按消息 payload schema 校验。它下方是每个 channel 参数一个输入项，以及一个由 channel 的 `servers` 填充的服务器选择器（host 和 path 变量取默认值），另有自由文本字段供填写其它 URL。感知协议的代码示例与表单严格同步，正如 HTTP 操作上的 curl、js 和 python 那样：channel 地址模板会填入你输入的参数值，因此复制出的 `wscat`、`WebSocket`、`kcat` 或 `mosquitto_pub` 代码与表单显示的内容一致。

实时连接只支持 WebSocket。在 `ws` 或 `wss` 绑定上，面板会连到解析出的 channel URL，显示连接状态，并逐帧记录日志、附上时间戳。AsyncAPI 3 从 API 一侧来陈述动作，面板也照此行事：`receive` 操作表示 API 从你这里接收消息，因此它有一个 **Send** 按钮用来发布编排好的 payload；`send` 操作只是向你推送消息，因此它只负责连接和记录。这里没有重连逻辑 —— socket 一旦关闭，就一直关闭，直到你再次连接。Kafka、MQTT、AMQP 以及其它所有协议则得到消息编辑器和可复制的 CLI 示例，面板也会在页面上明说这一点：Blume 不会在浏览器标签页里伪造 broker 连通性。

`asyncapi()` 的 `playground` 与 `openapi()` 的对应 —— 使用原生渲染器时默认开启，而 `false` 就是全部的关闭开关：

```ts blume.config.ts lineNumbers
reference: [asyncapi({ spec: "./asyncapi.yaml", playground: false })],
```

:::note
`playground.proxy` 对事件操作不适用。它转发的是 HTTP 请求，而 WebSocket 连接是从浏览器直连 URL 中指定的那台服务器，中间没有代理可插的位置。
:::

事件编辑器不收集任何 broker 凭据。每个操作页面的 **Authorization** 小节会说明 broker 期望什么，而 WebSocket 连接只携带 URL 里已有的内容。事件操作不会持久化任何东西。