Swagger vs OpenAPI 3.1:核心概念与规范演进
很多刚入行的同学一听到 Swagger 和 OpenAPI 就头大,觉得这俩词儿是不是同一个东西?可以这么理解,这俩确实是一家子,但属于“父子关系”或者说“进化关系”。
早些年,大家说的 Swagger 其实是 SmartBear 公司维护的一套工具集(包括 Swagger Editor, Swagger UI, Swagger Codegen)。后来,社区觉得这玩意儿太重要了,得有个统一的标准,于是 Swagger 的规范部分被捐赠给了 Linux 基金会,这就是 OpenAPI Initiative (OAI)。从那以后,“规范”这部分就改名叫 OpenAPI Specification (OAS),而 Swagger 则回归到了工具实现的层面。
咱们现在写代码,最该关注的是 OpenAPI Specification 3.1.0。这个版本是 2021 年 2 月发布的,别看它是 2021 年的,到现在依然是最新的稳定版。它最大的杀手锏是什么?就是完全兼容 JSON Schema 2020-12。
这意味着啥?意味着你在写 API 定义的时候,JSON Schema 里那些高级特性,比如 if/then/else 条件判断、更灵活的类型定义,在 OpenAPI 3.1 里都能用。以前 3.0 版本的时候,OpenAPI 对 JSON Schema 的支持是“阉割版”的,很多特性用不了,升级到 3.1 之后,这种割裂感就没了,定义复杂数据结构的时候爽得飞起。
规范演进带来的变化
在 3.1 版本里,有一个细节特别值得注意:type 字段支持数组了。
以前在 JSON Schema 里,你可以写 type: ["string", "null"] 来表示这个字段可以是字符串或者空值。但在 OpenAPI 3.0 里,这会被解析器报错。到了 3.1,这就完全合法了。这对于那些习惯用 null 表示空值的开发者来说,简直是福音。
另外,咱们社区里现在讨论最火的话题之一就是“要不要升级到 3.1”。我的建议是,新项目直接上 3.1,别犹豫。老项目如果接口多,可以慢慢迁,因为 3.1 对 3.0 的兼容性还是很好的,主要是底层 Schema 解析引擎变了。
🔧 实战技巧
注意:如果你在项目中看到有人还在用 Swagger 2.0 的注解(比如 @Api 这种),别犹豫,赶紧让他重构。Swagger 2.0 已经是“老古董”了,虽然还能跑,但很多新特性(比如上面说的 JSON Schema 兼容)都享受不到,而且现在的 SpringDoc 等主流工具链对 OAS 3.x 的支持才是最丝滑的。
下面是一个标准的 OpenAPI 3.1 的 YAML 片段,你可以感受一下它的结构,注意看 type 那里的写法:
openapi: 3.1.0
info:
title: 用户管理API
version: 1.0.0
description: 这是一个演示 OpenAPI 3.1 特性的示例
paths:
/users/{id}:
get:
summary: 获取用户信息
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: 成功返回用户详情
content:
application/json:
schema:
type: object
properties:
username:
type: string
# OpenAPI 3.1 的新特性:支持多类型定义
email:
type:
- string
- "null"
description: 邮箱可能是字符串,也可能是空值
role:
type: string
# 支持 JSON Schema 2020-12 的枚举写法
enum: ["admin", "user", "guest"]
Spring Boot 3集成Swagger:注解驱动与代码实战
现在主流的 Java 开发基本都跑在 Spring Boot 3 上了。在 Spring Boot 3 里集成 Swagger(准确说是集成 OpenAPI 规范实现),咱们不用老一套的 springfox-swagger2 了,那个东西在 Spring Boot 3 上简直是“雷区”,各种报错。现在业界的标准答案是用 springdoc-openapi。
简单来说,springdoc-openapi 就是目前连接 Spring Boot 和 OpenAPI 规范的最佳桥梁。它能自动扫描你的 Controller,把那些注解翻译成 OpenAPI 3.1 的文档。
快速集成步骤
咱们直接上干货。首先,在你的 pom.xml 里加上这个依赖。注意,Spring Boot 3 用的是 Jakarta EE 而不是 javax,所以一定要用 springdoc-openapi-starter-webmvc-ui 这个包。
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
加完依赖,你甚至不需要写任何配置类,直接启动项目,访问 http://localhost:8080/swagger-ui.html,文档就出来了。但这样生成的文档太简陋,咱们得用注解把它“武装”起来。
注解驱动实战
在 Spring Boot 3 里,咱们常用的注解都变了。以前是 @Api、@ApiOperation,现在换成 io.swagger.v3.oas.annotations 包下的注解了。
@Tag:给 Controller 分类,相当于以前的 @Api。
@Operation:描述一个接口方法,相当于以前的 @ApiOperation。
@Parameter:描述参数。
@Schema:描述数据模型(DTO/VO)。
来看一个完整的 Controller 和 DTO 示例,这是我在实际项目中常用的写法:
package com.example.demo.controller;
import com.example.demo.dto.UserDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/users")
@Tag(name = "用户管理", description = "用户相关的增删改查接口")
public class UserController {
@GetMapping("/{id}")
@Operation(summary = "根据ID获取用户", description = "通过用户ID查询详细信息,如果找不到返回404")
public UserDTO getUserById(
@Parameter(description = "用户唯一标识", required = true, example = "123")
@PathVariable Long id) {
// 模拟返回数据
UserDTO user = new UserDTO();
user.setId(id);
user.setUsername("coder_" + id);
user.setEmail("test@example.com");
user.setRole("admin");
return user;
}
@PostMapping
@Operation(summary = "创建新用户", description = "传入用户JSON对象,返回创建后的用户ID")
public String createUser(@RequestBody UserDTO userDTO) {
// 模拟创建逻辑
return "User created with id: " + userDTO.getId();
}
}
再来看看 DTO 的写法,这里用 @Schema 来定义字段含义和示例:
package com.example.demo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
@Schema(description = "用户数据传输对象")
public class UserDTO {
@Schema(description = "用户ID", example = "1001", accessMode = Schema.AccessMode.READ_ONLY)
private Long id;
@Schema(description = "用户名", example = "zhangsan", requiredMode = Schema.RequiredMode.REQUIRED)
private String username;
@Schema(description = "邮箱地址", example = "zhangsan@mail.com", nullable = true)
private String email;
@Schema(description = "角色", example = "admin", allowableValues = {"admin", "user"})
private String role;
// Getter 和 Setter 省略,实际开发记得加上
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
}
⚡ 效率提示
经验之谈提醒:很多新手在 Spring Boot 3 里加了依赖却发现访问不了 /swagger-ui.html。这时候先别慌,检查一下你的拦截器(Interceptor)或者安全框架(Spring Security)是不是把路径给拦了。在 Spring Security 里,你需要把 /swagger-ui/ 和 /v3/api-docs/ 这些路径放行,否则你看到的只会是一个空白页或者 403 错误。还有,别忘了生产环境一定要通过配置或者 Profile 把 Swagger 关掉,不然这就是个巨大的安全漏洞。
升级OpenAPI 3.1:兼容JSON Schema 2020-12与性能优化
如果你的项目正在从旧版迁移,或者你想用上最新的特性,那咱们就得聊聊怎么彻底拥抱 OpenAPI 3.1。正如前文提到的,这版本最大的亮点是完全兼容 JSON Schema 2020-12。
这听起来很技术,但对咱们开发者来说,最直观的好处就是写 API 定义的时候更“随心所欲”了。比如,以前定义一个字段,你想让它既是数字又是字符串,这在 3.0 里很难办,但在 3.1 里,直接利用 JSON Schema 的特性就能搞定。
兼容 JSON Schema 2020-12 的威力
咱们来看一个稍微复杂点的例子。假设你要定义一个“支付请求”,里面有个 amount 字段,有时候前端传字符串 "100.00",有时候传数字 100。在旧规范里,你可能需要写两个字段或者做兼容处理,但在 OpenAPI 3.1 里,你可以这样写:
openapi: 3.1.0
info:
title: 支付服务API
version: 2.0.0
paths:
/pay:
post:
summary: 发起支付
requestBody:
content:
application/json:
schema:
type: object
properties:
orderId:
type: string
# 重点在这里:利用 JSON Schema 2020-12 的多类型支持
amount:
type: [number, string]
description: 金额,可以是数字也可以是字符串格式的数字
# 还可以用 if/then 做复杂校验
paymentType:
type: string
enum: ["card", "transfer"]
cardNumber:
type: string
description: 如果是卡支付,这里填卡号
# 这里是 JSON Schema 的高级用法,在 3.1 中完美支持
if:
properties:
paymentType:
const: "card"
then:
required: ["cardNumber"]
这种灵活性是 3.1 版本带来的巨大提升,特别是对于那些对接了多种异构系统的场景。
大型项目的性能优化
咱们社区里经常有人吐槽,说 Swagger UI 在接口多了之后加载特别慢,甚至能把浏览器卡死。这确实是个痛点,尤其是微服务里接口成千上万的时候。
核心要点:解决性能问题,不能只靠换硬件,得靠“分而治之”。
- 分组(Grouping):别把所有的 Controller 都塞进一个文档里。
springdoc-openapi 支持通过 GroupedOpenApi 来分组。比如你可以把“用户相关”的接口分一组,把“订单相关”的分一组。这样每次加载只加载一部分,速度自然就快了。
- 按需加载:在 Swagger UI 的配置里,可以设置不自动展开所有接口模型。
- 缓存:如果你是用 CI/CD 生成的静态文档,直接把
api-docs 的 JSON 文件缓存起来,别每次请求都去反射扫描代码。
下面是一个在 Spring Boot 里配置分组的代码示例,这招非常管用:
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springdoc.core.models.GroupedOpenApi;
@Configuration
@OpenAPIDefinition(info = @Info(title = "电商平台API", version = "1.0"))
public class OpenApiConfig {
@Bean
public GroupedOpenApi publicApi() {
// 只扫描路径包含 /api/v1/public 的接口
return GroupedOpenApi.builder()
.group("公共接口")
.pathsToMatch("/api/v1/public/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
// 只扫描路径包含 /api/v1/admin 的接口
return GroupedOpenApi.builder()
.group("管理后台接口")
.pathsToMatch("/api/v1/admin/**")
.addOperationCustomizer((operation, handlerMethod) -> {
// 这里还可以针对特定组做定制化处理
return operation;
})
.build();
}
}
📖 学习建议
技术选型:关于工具链,市面上还有个热门话题是 Swagger Codegen 和 OpenAPI Generator 怎么选。可以这么理解,OpenAPI Generator 是 Swagger Codegen 的一个 fork(分支),现在社区更活跃,支持的语言和模板更新更快。如果你要生成客户端 SDK 或者服务端骨架,我建议直接用 OpenAPI Generator,别再守着老旧的 Codegen 了,不然生成的代码可能会有很多兼容性问题。而且,配合上 2024 年的趋势,很多 AI 工具已经开始支持直接读取这种标准文档来辅助生成代码了,文档写得好,AI 帮你干活儿都更利索。
4. 告别文档腐化:CI/CD集成与接口契约测试实战
打个比方,做开发最怕的就是“文档滞后”。代码早就改得面目全非了,结果 Swagger 页面上还挂着老的字段,前端同学对着文档调了半天,一跑就报错,这种锅背起来真的冤。这种情况在咱们圈子里叫“文档腐化”。
要解决这个问题,光靠开发人员的自觉性是不行的,人总会忘。咱们得靠流程,也就是把文档生成和校验嵌进 CI/CD 流水线里。
代码即文档,强制同步
现在的 OpenAPI 3.1.0(2021年2月发布,完全兼容 JSON Schema 2020-12)非常强调“注解驱动”。简单来说,就是代码写完,文档自动就出来了。咱们以 Spring Boot 项目为例,用现在最火的 springdoc-openapi 来演示。
假设我们有一个用户登录的接口,如果你不写注解,生成的文档就只有路径,参数说明全无。咱们得这么写:
package com.example.demo.controller;
import com.example.demo.dto.LoginRequest;
import com.example.demo.dto.LoginResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/auth")
@Tag(name = "认证管理", description = "用户登录、注册等相关接口")
public class AuthController {
@PostMapping("/login")
@Operation(summary = "用户登录接口", description = "通过用户名和密码获取JWT令牌")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "登录成功",
content = @Content(schema = @Schema(implementation = LoginResponse.class))),
@ApiResponse(responseCode = "401", description = "用户名或密码错误",
content = @Content(schema = @Schema(hidden = true)))
})
public ResponseEntity<LoginResponse> login(
@Parameter(description = "登录请求体", required = true)
@RequestBody LoginRequest request) {
// 模拟业务逻辑
if ("admin".equals(request.getUsername()) && "123456".equals(request.getPassword())) {
LoginResponse response = new LoginResponse();
response.setToken("fake-jwt-token-12345");
response.setExpiresIn(3600);
return ResponseEntity.ok(response);
}
return ResponseEntity.status(401).build();
}
}
配合的 DTO 也要把注解加好,这样生成的 components 才完整:
package com.example.demo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
public class LoginRequest {
@Schema(description = "用户名", example = "admin", required = true)
private String username;
@Schema(description = "密码", example = "123456", required = true, format = "password")
private String password;
// Getters and Setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
契约测试:守住API的底线
光有文档还不够,咱们得确保后端返回的数据结构没跑偏。这时候就要引入契约测试。咱们可以利用生成的 OpenAPI 文档作为“契约”,在测试阶段去校验接口返回是否符合规范。
这里推荐一个神器 rest-assured 结合 OpenAPI 解析。不过更简单的是直接用 openapi-diff 或者 swagger-request-validator。
在 CI 流水线中,咱们可以加一个步骤:每次构建时,导出最新的 OpenAPI JSON,然后跑一遍测试,看接口是否违反了契约。
这里给个基于 swagger-request-validator 的测试示例,这玩意儿能直接拿线上的请求去对比文档:
package com.example.demo;
import com.atlassian.oai.validator.OpenApiInteractionValidator;
import com.atlassian.oai.validator.model.Request;
import com.atlassian.oai.validator.model.Response;
import com.atlassian.oai.validator.model.SimpleRequest;
import com.atlassian.oai.validator.model.SimpleResponse;
import com.atlassian.oai.validator.report.ValidationReport;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@SpringBootTest
@AutoConfigureMockMvc
public class ContractTest {
@Autowired
private MockMvc mockMvc;
// 核心要点:这里加载的是咱们项目启动后生成的 OpenAPI 文档
// 实际项目中,你可以让 CI 先 curl 出 /v3/api-docs 保存为 json,然后再跑测试
private final OpenApiInteractionValidator validator = OpenApiInteractionValidator
.createFor("openapi.yaml") // 假设你已经把文档生成到了 classpath 下
.build();
@Test
public void validateLoginApiAgainstContract() throws Exception {
// 模拟一个请求
String requestBody = "{\"username\": \"admin\", \"password\": \"123456\"}";
MvcResult result = mockMvc.perform(post("/api/v1/auth/login")
.header("Content-Type", "application/json")
.content(requestBody))
.andExpect(status().isOk())
.andReturn();
// 构造 Request 和 Response 给校验器
Request request = new SimpleRequest.Builder("POST", "/api/v1/auth/login")
.withContentType("application/json")
.build();
MockHttpServletResponse servletResponse = result.getResponse();
Response response = new SimpleResponse.Builder(servletResponse.getStatus())
.withContentType(servletResponse.getContentType())
.withBody(servletResponse.getContentAsString())
.build();
// 执行校验
ValidationReport report = validator.validate(request, response);
// 如果有报错,这里会打印出来,比如缺字段、类型不对等
if (report.hasErrors()) {
report.getMessages().forEach(msg -> System.out.println("契约校验失败: " + msg.getMessage()));
}
assertThat(report.hasErrors(), is(false));
}
}
📖 学习建议:千万不要只在本地生成文档。一定要在 Jenkins 或 GitHub Actions 的 Pipeline 里加一个 Job,专门负责 mvn verify 或者 npm run generate-docs,然后把生成的 openapi.json 作为构建产物保存下来。这样谁改坏了接口,CI 直接挂红灯,想混过去都难。
---
5. 生产环境安全:禁用Swagger与防信息泄露配置
这事儿我必须得重点强调一下:很多新手甚至工作几年的老鸟,上线的时候压根不管 Swagger 的事儿,直接把 http://api.xxx.com/swagger-ui.html 暴露出去了。
这就好比你把家里的保险箱密码贴在门口,还画了个箭头指向卧室。Swagger 页面里不仅有接口路径,还有你定义的 DTO 结构、甚至有时候还有示例数据(比如真实的 Token 示例)。如果被不怀好意的人扫到了,那就等着被脱裤吧。
不同环境的动态配置
咱们的目标很明确:开发环境(Dev)和测试环境(Test)可以随便看,生产环境(Prod)必须关闭。
在 Spring Boot 中,最优雅的方式是利用 @Profile 或者配置文件条件。咱们看代码,这是最稳妥的写法。
首先,确保你的 pom.xml 里依赖的是 springdoc-openapi-starter-webmvc-ui。
然后,咱们写一个配置类,通过 @Profile 来控制 Swagger 的行为:
package com.example.demo.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class OpenApiConfig {
/**
* 只在 dev 和 test 环境下激活这个 Bean
* 生产环境没有这个 Bean,Swagger 就不会生效
*/
@Bean
@Profile({"dev", "test"})
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("我的后端API文档")
.version("v1.0.0")
.description("仅用于开发和测试环境调试"));
}
}
但这还不够,即使没加载 OpenAPI Bean,springdoc 相关的静态资源可能还是能访问。咱们得彻底把 UI 的路径给堵上。
在 application-prod.yml 中,直接把 springdoc 相关的开关全部关掉:
# application-prod.yml
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
# 防止有人通过 actuator 或者其他方式访问
进阶:通过拦截器彻底封死
有时候配置文件不生效,或者你想更保险一点。咱们可以写个拦截器,凡是访问 /swagger* 或者 /v3/api-docs 的,直接返回 404 或者 403。
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SwaggerBlockInterceptor())
.addPathPatterns("/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**");
}
private static class SwaggerBlockInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 简单粗暴,直接拦截
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
// 或者返回 403 Forbidden
// response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false; // 终止请求
}
}
}
求职必备:如何防止泄露?
如果面试官问你“生产环境怎么处理 Swagger”,你别只说“删掉依赖”。那太 low 了,而且万一以后要调试还得加回来。
📖 学习建议:最佳实践是通过 Maven Profile 或者 Spring Profile 来控制依赖和作用域。
如果是 Maven,你可以把 Swagger 的依赖 scope 设置为 provided 或者只在 dev 的 profile 里引入。
但是最推荐的还是我上面写的,利用 springdoc.swagger-ui.enabled=false 这个配置项。因为 OpenAPI 3.1.0 的规范支持非常完善,但安全配置一定要做在代码之外,通过环境变量或配置文件控制,这样最灵活,也最安全。
---
6. 未来趋势:AI辅助生成与AsyncAPI异步接口融合
咱们做技术的,眼光得放长远点。现在的 Swagger/OpenAPI 虽然好用,但也不是完美无缺。根据我最近在开发者社区看到的热门讨论,以及 2024 到 2026 年的技术趋势,有两个方向咱们必须得关注:AI 辅助生成和异步接口(AsyncAPI)的融合。
AI 辅助:从“写代码”到“说需求”
以前咱们写 API 文档,得一个注解一个注解地敲。现在不一样了,大语言模型(LLM)火了之后,已经有人开始尝试 AI 辅助生成 API 定义 了。
想象一下,你对着 AI 说:“我要一个用户注册的接口,需要邮箱、密码,返回用户ID和创建时间。”
AI 直接给你吐出一段符合 OpenAPI 3.1.0 规范的 YAML 代码。
openapi: 3.1.0
info:
title: User Registration API
version: 1.0.0
paths:
/api/v1/users/register:
post:
summary: Register a new user
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
example: "user@example.com"
password:
type: string
format: password
example: "Str0ngP@ss!"
required:
- email
- password
responses:
'201':
description: User created successfully
content:
application/json:
schema:
type: object
properties:
userId:
type: integer
format: int64
example: 101
createdAt:
type: string
format: date-time
这比手写快多了吧?而且现在的趋势是,这种 AI 工具还能智能检测文档逻辑漏洞,比如你定义了 password 字段,但忘了加 minLength 或者 format: password,AI 可能会提示你增强安全性。这就是所谓的 安全左移(Shift Left Security),在写文档的时候就把坑填上。
AsyncAPI:搞定 WebSocket 和 Kafka
咱们现在的 Swagger(OpenAPI)主要管的是同步请求,也就是 HTTP 那一套。但现在的系统,微服务之间全靠消息队列(Kafka、RabbitMQ)或者 WebSocket 通信。
如果还是用 OpenAPI 去描述异步接口,那就太拧巴了。所以社区推出了 AsyncAPI。
核心要点:AsyncAPI 的语法设计和 OpenAPI 非常像。如果你会写 Swagger,学 AsyncAPI 分分钟的事。
比如,你要描述一个 Kafka 的 Topic,以前你没法写在 Swagger 里,现在用 AsyncAPI 可以这么写(这是一个简单的示例):
asyncapi: 2.6.0
info:
title: User Signup Service
version: 1.0.0
channels:
user/signedup:
subscribe:
summary: Receive information about user signup
message:
name: UserSignup
contentType: application/json
payload:
type: object
properties:
userId:
type: string
format: uuid
signedUpAt:
type: string
format: date-time
现在的趋势是,统一管理。大家希望在一个门户里,既能看到 RESTful 的同步接口,又能看到 MQ 的异步事件。虽然目前这两个规范还是独立的,但工具链正在融合。比如 OpenAPI Generator 和 AsyncAPI Generator 的命令行参数都越来越像,甚至有些平台开始尝试在一个 UI 界面里同时渲染两种文档。
无代码与低代码的冲击
还有一个很有意思的趋势,就是 无代码/低代码平台 对 API 文档的依赖。
现在的低代码平台,很多都支持直接导入 OpenAPI 文档(特别是 3.0 或 3.1 版本),然后自动生成前端表单或者后端逻辑。这意味着,咱们写的 API 文档,未来可能不仅仅是给前端看,还是给低代码引擎“吃”的配置文件。
💡 经验总结:既然知道 AsyncAPI 是未来,我建议你现在做微服务设计的时候,尽量把 事件(Event) 和 资源(Resource) 区分开。如果是事件驱动的部分,哪怕现在先不写 AsyncAPI 文档,也要在代码注释或者 README 里按照 AsyncAPI 的思维方式去描述消息结构。这样等以后工具链成熟了,你迁移起来就是分分钟的事,不用重构整个文档体系。