Spring REST Docs 介绍
Spring REST Docs 是一个为 Spring 项目生成 API 文档的框架,它通过在单元测试中额外添加 API 信息描述,从而自动生成对应的文档片段。
本文会以一个最简单的示例介绍如何在一个 Spring Boot 应用中使用 Spring REST Docs,并在最后与目前最常见的 SpringFox 进行一些对比,分别介绍其特点和优劣。
基础准备
首先需要一个 Spring Boot 项目,并通过 MockMvc 编写一些简单的测试。
|
在上面代码中提供了一个最简单的 Controller,其接收请求参数中的 name
属性,并返回一个包含 code
和 msg
的 Result 对象。
接下来需要为其编写一个测试:
|
在这里使用了 JUnit5 和 Spring 的 MockMvc 编写 API 测试,只是简单的请求这个 API 并校验返回值。
完成以上工作,就可以开始通过修改测试代码,为这个 API 自动生成相关的描述文档了。
配置 Spring REST Docs
当使用 MockMvc 时,只需要添加 spring-restdocs-mockmvc
依赖:
|
之后,需要修改测试代码,添加对应的文档支持:
|
- 在
@ExtendWith
中增加RestDocumentationExtension
(JUnit5 的 Extension 相当于 JUnit4 中的 Rule)。 - 将
MockMvc
由直接注入改为手动构建,增加documentationConfiguration(restDocumentation)
配置。 - 在执行测试的最后,调用
andDo(document("hello"))
给测试调用所生成的文档命名。
构建文档
完成配置后,运行 mvn clean package
进行构建,当测试运行成功后查看 target/generated-snippets
下出现的一系列 adoc 文档:
其中 curl/httpie-request.adoc
记录了测试请求通过 curl 和 httpie 的调用方式, http-request/response.adoc
记录了测试请求和返回的 raw 信息,request/response-body.adoc
记录了请求和返回的 Payload。
不过这些都只是一个个文档片段,还需要将其拼凑到一起才能成为一份完整的 API 文档,框架本身不提供直接生成完整文档的功能,所以需要编写一个文档主页并引入这些自动生成的文档片段。
默认的文档主页可以放在 src/main/asciidoc/index.adoc
中,例如:
|
其中最重要的一行是 operation::hello[]
,它表示将 hello 下的所有片段都引入进入,或者也可以指定 operation::hello[snippets='curl-request,http-request,http-response']
的方式只引入部分代码片段。
编写好文档主页后,需要使用 asciidoctor-maven-plugin
使其可以在打包时与片段整合起来,并生成最终的 HTML 文件:
|
此时再次运行 mvn clean package
之后,可以看到 target/generated-docs
下生成了最终的网页,其最终效果如下图所示。
至此,最简单的请求文档便构建完成了。
和 SpringFox 的对比
相较于传统且更流行的 SpringFox(Swagger),Spring REST Docs 的实现方式相当新颖,而且有着鲜明的区别,那么不妨在此列举一下两者的区别以及优劣,以便更好的根据实际需求和使用场景选择最合适的工具。
首先,两者最大的区别就在于根本定位,SpringFox 的定位是和应用一起启动的在线文档,文档的浏览者可以很简单的填写表单并发起一个真实的请求,而 Spring REST Docs 更倾向于导出一份离线文档作为展示,并配合 curl、httpie 这种工具请求真实部署的服务。
其次,SpringFox 最大的特点是使用简单,只需要在源码中增加一些描述性的注解即可完成整份文档,而使用 Spring REST Docs 的前提条件是需要在项目中对 API 进行单元测试,并且要保证测试是可以稳定执行的,这对于很多团队来说无疑增加了很高的门槛。
但是对于已经有完整单元测试的团队来说,增加额外的文档描述几乎和 SpringFox 一样简单,并且还能完整的去除源码依赖。除此之外,依靠测试本身也正是 Spring REST Docs 的最大亮点:
首先,每一次测试都是一个真实的请求(不追究 MockMvc 具体实现细节),它所对应的请求和返回都是真实的,可以轻松将其记录下来作为 Demo 展示。而 SpringFox 只是对 Controller 层的方法进行了扫描,却无法感知 Interceptor、MethodArgumentResolver 这类中间件的存在,只能通过一些全局配置进行额外的描述。
其次,每一次测试也都是一个独立的请求,使得 Spring REST Docs 可以描述同一个 API 在不同请求参数中返回的不同结果的场景(例如成功或是各种失败情况),而 SpringFox 只能描述单一的方法签名和返回值 Model,却无法描述其具体可能出现的场景。
最后,错误的文档比没有文档还要糟糕,所以 Spring REST Docs 不仅仅是做 API 文档化,同时也是在做 API 契约化,如果 API 的实现修改破坏了已有的测试,哪怕仅仅是字段定义,都会导致测试的失败。这可以督促 API 的制定者保证对外提供的契约,也可以让 API 的使用者更加放心。
所以相比之下,如果一个技术氛围良好,对服务严格负责,且愿意尝试 API 单元测试和契约测试的团队来说,我更推荐使用 Spring REST Docs,而如果只是在已有的服务上增加描述性的文档,SpringFox 会是性价比更高的选择。