用代码写接口文档 Spring Rest Docs

本文介绍了Spring Rest Docs,一个用于用代码编写接口文档的工具。它遵循测试驱动开发的理念,通过编写测试来生成文档。文章通过一个小例子展示了如何使用Spring Rest Docs创建GET和POST接口的文档,包括如何添加Maven依赖、编写测试、生成和组织adoc文件,以及如何添加字段信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本次 more time 为读者👬们介绍 Spring Rest Docs,这是一个用代码写接口文档的工具。
先看看效果
Jietu20191103-215840.jpg

Jietu20191103-215921.jpg
swagger 不同,swagger 倾向于自动生成,这个还是得写。至于怎么写呢?Spring Rest Docs 的 Github 给出了更加明确的定义:测试驱动的文档。

说到测试驱动,不得不提测试驱动开发 TDD。总之TDD的核心就是:先写测试,后写代码,这样即能保证代码是对的,又敢重构。
那么这个Spring Rest Docs 这个测试驱动的文档是什么意思呢?
写测试,生成文档。
生成文档的前提是测试通过。

流程就是:写测试 -> 写能通过测试的代码 -> 通过测试 -> 生成文档。

问题在 能通过测试的代码 上,这里有两种选择。

  1. 符合业务需求的正确代码
  2. 能通过测试的类似Mock代码

如果选择1,那么这份接口文档的交付时间就是正式代码写好之后
如果选择2,那么这个Mock代码就很浪费,因为mockserver 有 wiremock 解决方案,简单的CRUD还有 json-server
之后还有会有 Spring Cloud Contract , 它实现了消费者驱动契约。
如何将这些技术统一起来,形成一个最佳的工作流,是我最近思考的问题。

光就 Spring Rest Docs 来说
方案1:这份文档是用 CI生成的,这份文档会随着测试驱动开发不断丰富,每新写一个 controller 就丰富这个文档,供用户看,是不断变化的。

方案2:感觉是一种反模式,我第一次就是这么用的。先写 controller,无视输入,直接返回一个值,再写好全部测试,有输入输出,最后来生成。这个好处就是可以立刻交付文档,并且因为通过了测试,这一份代码也可以拿去给其他人当mockserver。

本文的小demo并不是涉及复杂逻辑,主要是带领读者👭们看一看这么用。

小王接到了一个任务,写两个接口,一个GET一个POST
GET 算平方
长这样 GET /sqr?x=2 返回 {"ans": 4}
POST 算和
长这样 POST /sum/3 {``"y": 5} 返回 {"ans": 8}
小王说着太简单了,瞬间写好了——测试,用了mockmvc,这样就先不需要实例化 controller 了。

@Test
fun shouldReturn4whenXis2() {
	mockMvc.perform(get("/sqr?x=2"))
			.andExpect(jsonPath("$.ans", `is`(4)))
}

@Test
fun shouldReturn8whenXis3andYis5() {
	val req = """
		{
			"y": 5
		}
	""".trimIndent()
	mockMvc.perform(post("/sum/3")
			.content(req)
			.contentType(MediaType.APPLICATION_JSON))
			.andExpect(jsonPath("$.ans", `is`(8)))
}

写好之后小王点了一下运行,啥也没写,果然变红,于是开始写 controller,过了一会儿,写好了。

@GetMapping("/sqr")
fun sqr(@RequestParam x: Int) = Res(x * x)

@PostMapping("/sum/{x}")
fun sum(@PathVariable x: String, @RequestBody req: Req) = Res(x.toInt() + req.y)

再点一下测试,变绿了,都通过了测试,完美。
这时小王想用上了 Spring Rest Docs 来声明文档,首先引入 Maven依赖。如果用 Spring Boot Starter 直接勾就好了,如果是老项目,请点击阅读原文看语雀上的附录。

之后给测试加点料
类前面加上 @AutoConfigureRestDocs ,这时候里面的 mockmvc 已经不是原来那个 mockmvc了,它变得更强了。

@AutoConfigureRestDocs
class DemoApplicationTests {

之后给测试后面加上 andDo(Document("docname"))

.andExpect(jsonPath("$.ans", `is`(4)))
.andDo(document("sqr"))

之后再次运行测试,神奇的事情发生了,在 target 下生成了 generated-snippets 文件夹,里面还有相关的子文件夹,如 sqr, sum,里面生成相关的 adoc 文件。
adoc文件使用了 asciidoc 的语法,比 markdown 功能更多。具体可以参考 Asciidoc官方网站
但是生成这些片段也很麻烦,莫非 cat *.adoc 把他们整理起来?
当然不用。
在 src/main 下建一个 asciidoc 文件夹,然后新建一个 index.adoc 文件,大概长这样

= 接口文档
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:

== sqr
operation::sqr[]
== sum
operation::sum[]

前面是一些设置,和LaTeX类似。然后 == 是二级标题, operation 是把 snippets 组合起来。
最后运行
mvn package
就会发现在 target下多了一个 generated-docs 文件夹,里面有一个index.html,这就是生成的文档。
不过问题又来了,这就只有一个样例输入样例输出也太弱了,字段类型都没有。
当然有,只不过要再加点编码。

字段信息有 requestParameter, pathParameters, requestFields 和 responseFields 这几类,用法都是先限定名字,然后用 description() 描述内容,代码如下

.andDo(document("sqr",
				requestParameters(
					parameterWithName("x").description("输入的数")
				),
				responseFields(
					fieldWithPath("ans").description("答案")
				)))
.andDo(document("sum",
				pathParameters(
					parameterWithName("x").description("第一个加数")
				),
				requestFields(
					fieldWithPath("y").description("第二个加数")
				),
				responseFields(
					fieldWithPath("ans").description("它们的和")
				)))

这样便完成了字段的编写

如果不想引入全部 snippets,可以用
operation::index[snippets='curl-request,http-request,http-response']
这种语法来指定,

补充

  1. 以后阅读原文会链接到语雀上,毕竟公众号连外链都不行,很闭塞

代码附录

  1. 需要加的 pom
		<dependency>
			<groupId>org.springframework.restdocs</groupId>
			<artifactId>spring-restdocs-mockmvc</artifactId>
			<scope>test</scope>
		</dependency>

			<plugin>
				<groupId>org.asciidoctor</groupId>
				<artifactId>asciidoctor-maven-plugin</artifactId>
				<version>1.5.8</version>
				<executions>
					<execution>
						<id>generate-docs</id>
						<phase>prepare-package</phase>
						<goals>
							<goal>process-asciidoc</goal>
						</goals>
						<configuration>
							<backend>html</backend>
							<doctype>book</doctype>
						</configuration>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>org.springframework.restdocs</groupId>
						<artifactId>spring-restdocs-asciidoctor</artifactId>
						<version>${spring-restdocs.version}</version>
					</dependency>
				</dependencies>
			</plugin>

欢迎关注在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值