一、为何要写接口文档
很多程序员都会写API,但不是每个程序员都会写API文档,也不是每个程序员都能写好API文档,很多人其实并不看重文档的编写,这其实是错误的,文档是我们不同工种(开发、测试)之间交流的主要参考,如果你文档不写或者写的不好,那么会多非常多无效的沟通,不知道你有没有遇到过,你的一个枚举字段没有文档说明,每个人都要来问一下,你这个枚举有多少有效值,你是不是很烦躁,你的同事比你更烦躁,如果你详细的写好了,每个人看你的文档就能看懂,没有人再来打扰你,如果每个人都把文档写好了,整个公司便会少很多无效的沟通,效率自然而然提升,我们的工作体验也会好很多。
二、接口文档框架
这里我主要给大家介绍一款框架,Swagger,这个框架与代码完美结合在一起,通过特定的方式,将注解里的东西生成一个好看的html页面展现大家。但是本篇我们并不介绍这个框架,而是介绍在此框架基础上的一个框架->knife4j.
三、使用及效果
引入依赖
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.8</version>
</dependency>
添加配置
/**
* Swagger配置
*
* @author huaijie.chen
*/
@Configuration
@EnableSwagger2WebMvc
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.billion.pay.omc.system.web.controller"))
.paths(any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("支付平台-OMC系统服务")
.description("支付平台-OMC系统服务")
.termsOfServiceUrl("http://www.billion.com")
.contact(new Contact("Pay Tech Team", "http://www.billion.com", "chenhuaijie@aliyun.com"))
.license("供公司内部使用")
.version("1.0")
.build();
}
}
介绍一下几个注解:
@Api 修饰controller类的
@ApiOperation 修饰controller里的方法的
@ApiParam 修饰方法的参数的
@ApiModel 修改参数类的
@ApiModelProperty 修饰参数类里的字段的
举例如下:
项目启动后,只需在项目路径后加上/doc.html就可以进入到文档页面,并可以调试
找个接口看一下:
在调试这里,可以真正发起请求调试我们的代码,开发调试利器
这个框架比Swagger的好处是界面更加合理,通过这种tab的方式,可以同时打开很多个接口的文档,还有这种全局搜索可以快速的找到一个接口,还可以到处离线文档。
四、文档聚合
我们在工作中,不会只开发一个服务,很多时候我们开发了几十上百个服务,如果一个服务一个文档地址,维护起来是非常痛苦的,在分布式项目中,我们经常会使用SpringCloud来管理微服务,接下来介绍一个文档聚合案例。
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-aggregation-spring-boot-starter</artifactId>
<version>2.0.8</version>
</dependency>
配置:
/**
* @author Administrator
*/
@Configuration
@EnableSwagger2WebMvc
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfig {
@Bean
@Order(value = 1)
public Docket groupRestApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(groupApiInfo());
}
private ApiInfo groupApiInfo() {
return new ApiInfoBuilder()
.title("支付平台-API文档")
.description("支付平台-API文档")
.version("1.0")
.build();
}
}
/**
* @author chenhuaijie
*/
@Slf4j
@Primary
@Component
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private DiscoveryClient discoveryClient;
@Override
public List<SwaggerResource> get() {
Map<String, ZuulProperties.ZuulRoute> map = zuulProperties.getRoutes();
Set<String> services = map.keySet();
if (CollectionUtils.isEmpty(services)) {
return new ArrayList<>(0);
}
List<SwaggerResource> resources = new ArrayList<>();
for (String service : services) {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(service);
if (!CollectionUtils.isEmpty(serviceInstances)) {
resources.add(swaggerResource(service, "/" + service + "/v2/api-docs"));
}
}
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
在这里,我是通过zuul网关技术将请求转发到具体子服务的,最终的聚合效果如下:
在箭头的地方可以切换到不同的服务,切换后可以查看文档及发起请求。
总结:
曾经有一位行业前辈,也是我曾经的一个领导跟我说,写文档,你要站在使用者的角度来写,把他们当成一个白痴,不要怕麻烦,写的越详细越好,这样不仅帮到了别人,同时也给自己省了不少事情,我非常同意这个观点。我也希望我要接触到的东西,人家写的文档也能把我当成一个傻子,让我不用一遍一遍去问作者一些低端的问题。
程序员不光要会写代码,写文档也是一项重要技能。