本文档内容由 AI 生成,如有不准确之处,请以 Milky 官方文档为准。
Milky IR 是 Milky 在类型定义与 OpenAPI 之外提供的一种中间表示(Intermediate Representation)。本仓库包含对 Milky IR 的系统介绍,并且提供各个正式版的 Milky 协议对应的 IR 文件存档。
如果说 OpenAPI 更适合通用 API 工具链,JSON Schema 更适合做结构校验,那么 Milky IR 的目标就更直接一些:以更少的歧义、更稳定的结构,向代码生成器、SDK 生成工具和协议实现提供一份足够简洁的“可消费模型”。
它并不是对外通信协议本身的一部分,也不是用来取代文档的另一套规范,而是从 Milky 的类型系统中提取出的、面向实现者的结构化描述。
在真实的工程场景中,直接消费 OpenAPI 或原始类型定义并不总是轻松的事情。
- OpenAPI 的表达能力很强,但对于某些语言的代码生成器而言,过强的泛化能力也意味着更高的适配成本。
- 原始类型定义最贴近规范本身,但通常绑定具体语言或具体实现细节,不一定适合被其他工具链直接消费。
- 对于带判别字段的联合类型、可选字段、默认值、结构体引用等信息,很多生成器真正需要的是一种更“平铺”、更“显式”的描述方式。
Milky IR 解决的正是这个问题。它将 Milky 中常用的结构信息整理为一套统一模型,使实现者可以用较低的心智负担完成以下工作:
- 生成 SDK 或类型定义
- 生成序列化 / 反序列化代码
- 构建文档索引或调试工具
- 为不同语言编写稳定的 Codegen 后端
Milky IR 主要描述三类内容:
Milky 的公共结构体会以统一形式出现在 commonStructs 中。对于普通对象,IR 会直接给出结构体名称、描述和字段列表;对于联合类型,则会额外标明它的判别字段以及各个分支的派生信息。
字段本身只保留实现层最常用的信息,例如:
- 字段名
- 字段描述
- 是否为数组
- 是否可选
- 默认值
- 字段类型
其中字段类型被收敛为三种:
scalar:基础标量类型,如int32、int64、string、boolenum:枚举值列表ref:对其他公共结构体的引用
这种约束是有意为之。Milky IR 并不追求完整复刻底层类型系统,而是优先保证生成器处理起来简单、明确、稳定。
Milky 的 API 会按分类整理在 apiCategories 中。每个分类包含若干接口,每个接口会描述:
- 接口端点
- 接口说明
- 请求字段列表
- 响应字段列表
这意味着一个生成器即使不理解完整的 OpenAPI 语义,也可以仅凭 Milky IR 生成相当可用的请求、响应和调用层代码。
Milky IR 还会携带 milkyVersion 与 milkyPackageVersion,用于标记其所对应的 Milky 规范版本与类型包版本。对于需要做缓存、增量更新或版本对齐的工具来说,这一点很有用。
联合类型往往是代码生成中最麻烦的部分之一,也是 Milky IR 相比通用描述格式更有针对性的地方。Milky IR 将联合类型分为两类:
当一个联合类型的各个分支本身就是彼此独立的结构时,IR 会将其表示为 plain union。每个分支都有自己的判别值和字段集合,适合直接映射为不同语言中的枚举变体、sealed class、tagged union 等形式。
当一个联合类型具有稳定的公共字段,并通过 data 字段承载具体分支内容时,IR 会将其表示为 withData union。此时公共字段会单独提取为 baseFields,各个分支则以派生类型的形式记录。
这样的拆分对代码生成非常友好,因为它更接近许多现代语言的实际建模方式:公共部分保持一致,差异部分集中在派生载荷中。
如果你正在做以下事情,那么 Milky IR 往往会比直接消费 OpenAPI 或底层类型定义更省力:
- 为 Milky 生成各种语言的数据模型
- 实现针对联合类型有特殊处理需求的序列化逻辑
- 编写面向协议实现者的检查、预览或转换工具
反过来说,如果你的目标是接入通用 API 平台、导入第三方接口管理工具,或者复用成熟的 OpenAPI 生态,那么 OpenAPI 仍然会是更自然的选择。
Milky IR 是一份面向实现者的、对 Codegen 更友好的 Milky 中间表示。
它从 Milky 现有的类型定义中提取出最核心、最稳定、最适合工程消费的信息,尽量减少通用格式带来的额外解释成本。如果你正在为 Milky 生态编写 SDK、生成器或基础设施工具,那么 Milky IR 会是一份非常值得优先考虑的输入数据源。