14、API文档生成:OpenAPI/Swagger集成、Ktor插件配置、文档自动生成
说实话,很多团队在API文档这件事上吃过亏。
我见过最夸张的项目,接口文档和代码完全是两个世界的东西。前端照着文档调接口,调一个崩一个。为什么?文档是三个月前写的,代码早就改了三轮了。
所以这次我们聊聊怎么让文档和代码保持同步。说白了,就是用OpenAPI规范,配合Ktor的插件,让文档自动生成。你只管写代码,文档的事交给工具。
为什么选OpenAPI?
OpenAPI(以前叫Swagger)现在已经是API描述的事实标准了。它用JSON或YAML来描述你的接口——路径、参数、请求体、响应格式,全都写得清清楚楚。
好处很明显:
- 前端可以拿这个文档直接生成客户端代码
- 测试团队可以基于文档写自动化测试
- 新同事上手,看文档比翻代码快得多
我个人习惯是,只要对外暴露的接口,必须配OpenAPI文档。哪怕只是内部服务之间调用,我也会生成一份。你想想看,半年后你自己回头看自己写的接口,没有文档真的会抓狂。
Ktor的OpenAPI插件
Ktor官方提供了一个插件叫io.ktor:ktor-server-openapi。它的作用很简单:根据你写的路由代码,自动生成OpenAPI规范文档。
配置起来也不复杂。先加依赖:
// build.gradle.kts
implementation("io.ktor:ktor-server-openapi:$ktor_version")
然后在Application模块里安装插件:
fun Application.module() {
install(OpenAPI) {
info {
title = "我的Android后端API"
version = "1.0.0"
description = "这是为Android客户端提供的RESTful API"
}
server {
url = "http://localhost:8080"
description = "本地开发环境"
}
}
}
嗯,这里要注意:插件默认会扫描你所有的路由,自动提取路径、方法、参数。但如果你用了自定义的序列化方式,可能需要额外配置一下。
文档自动生成的核心逻辑
我画了一张图,帮你理解整个流程:
流程其实很清晰:你写路由 → 插件扫描 → 生成OpenAPI规范 → Swagger UI渲染成可视化页面。中间不需要你手动写任何文档描述。
给接口添加描述信息
自动生成虽然方便,但光靠代码扫描,有些信息是拿不到的。比如接口的用途、参数的含义、返回值的说明。这些需要你手动补充。
Ktor的OpenAPI插件支持用注解或DSL来添加描述。我个人更推荐DSL的方式,因为和Ktor的路由风格更统一:
get("/users/{id}") {
// 描述这个接口
description = "根据用户ID获取用户信息"
request {
pathParameter<String>("id") {
description = "用户的唯一标识符"
example = "user_12345"
}
}
response {
body<UserResponse> {
description = "用户信息对象"
}
status(HttpStatusCode.OK) {
description = "成功返回用户信息"
}
status(HttpStatusCode.NotFound) {
description = "用户不存在"
}
}
// 实际的业务逻辑
val userId = call.parameters["id"] ?: return@get call.respondText("Missing id")
val user = userRepository.findById(userId)
if (user != null) {
call.respond(user)
} else {
call.respondText("User not found", status = HttpStatusCode.NotFound)
}
}
你看,每个参数、每个响应码都配了说明。前端看到这个文档,就知道该传什么、会得到什么。
Swagger UI的集成
光有OpenAPI规范还不够,你得有个界面让人看。Swagger UI就是干这个的。
Ktor官方也提供了Swagger UI插件:
implementation("io.ktor:ktor-server-swagger:$ktor_version")
安装方式类似:
install(SwaggerUI) {
swaggerUrl = "/openapi.json" // 指向OpenAPI规范文件
path = "/docs" // Swagger UI的访问路径
title = "我的API文档"
}
启动服务后,访问 http://localhost:8080/docs,就能看到漂亮的交互式文档页面。你可以在页面上直接测试接口,非常方便。
处理复杂的数据结构
如果你的接口返回的是嵌套对象,或者用了泛型,OpenAPI插件也能处理。但需要你定义好数据类,并且用@Serializable注解标记:
@Serializable
data class UserResponse(
val id: String,
val name: String,
val avatar: String? = null,
val level: Int = 1,
val createdAt: String
)
@Serializable
data class PaginatedResponse<T>(
val data: List<T>,
val page: Int,
val total: Int,
val hasMore: Boolean
)
插件会自动识别这些数据类的字段类型、是否可空、默认值,然后生成对应的JSON Schema。你不需要额外写任何映射代码。
版本管理与多文档
项目大了之后,你可能会有多个版本的API。比如v1和v2同时存在。OpenAPI插件支持多文档配置:
install(OpenAPI) {
// 默认文档
info {
title = "API v1"
version = "1.0.0"
}
// 额外文档
document("v2") {
info {
title = "API v2"
version = "2.0.0"
}
server {
url = "http://localhost:8080/api/v2"
}
}
}
这样每个版本的接口可以独立生成文档,互不干扰。前端可以根据自己对接的版本,只看对应的文档。
避坑指南
最后分享几个我踩过的坑:
- 路由顺序问题: 如果你有多个路由匹配同一个路径,插件可能只生成第一个的文档。我建议把精确匹配的路由放在前面,模糊匹配的放后面。
- 泛型擦除: Kotlin的泛型在运行时会被擦除,插件可能无法正确识别泛型参数的类型。这时候需要手动指定
@TypeInfo注解来辅助。 - 自定义序列化: 如果你用了非标准的JSON序列化方式(比如自定义的Serializer),插件可能无法正确推断字段类型。需要额外配置
schemaGenerator。
说实话,这些问题都不难解决。但第一次遇到时确实会卡住一会儿。我的建议是:先跑通最简单的例子,再逐步加复杂功能。这样出了问题,你能快速定位是哪个环节的问题。
好了,关于API文档自动生成,核心内容就这些。你只要把路由写清楚,配上必要的描述信息,剩下的交给插件就好。文档和代码同步,再也不用担心「文档过期」这种破事了。
核心要点回顾:
- OpenAPI是API描述的标准,Ktor通过插件支持自动生成
- 用DSL给接口、参数、响应添加描述信息
- Swagger UI提供可视化交互页面,方便测试
- 生产环境记得关闭或保护Swagger UI
- 多版本API可以独立生成文档