Skip to content

导入 Swagger 2 接口文档到 ApiFox 时接口重复的问题

🏷️ Swagger

项目中使用 Swagger 2 和 ApiFox 来管理文档。Swagger 依赖的版本是

  • springfox-swagger2:2.9.2
  • springfox-swagger-ui:2.9.2

但是更新了 ApiFox 的客户端版本( 2.2.19 )后发现:导入时相同路由的接口会自动覆盖。如果只导入一个服务,不会出现接口路由重复的情况。不过若项目中有多个服务,而且碰巧路由重复了,就会出现覆盖别的服务的接口文档的情况。之前的版本导入时可以设置为相同目录下且路由相同时才覆盖,但是新版没有这个设置项。另外数据模型的导入也有类似的问题。

根据 ApiFox 的更新日志,在 2.2.21-alpha.1 版中已经添加了 导入接口时,接口的匹配规则会根据每个目录的 接口唯一标识 进行匹配 的优化。

等这个版本发布后,应该就不会再有本文中的问题了。

导入接口时有一个 接口唯一标志 的配置项,其中常用的是 Method & PathOperationId 。大多数情况下都是使用 Method & Path 的方式,所以导致了上面的问题。

使用 OperationId 作为接口唯一标志倒是可以解决这个问题。在 Swagger 2 的 @ApiOperation 注解中设置 nickname 就可以了。

java
@ApiOperation(value = "用户登录", nickname = "user-service-login-post")

不过现有的接口都没有设置这个值,采用这种方式的话改动范围太大了,最后放弃了这种方案。

在导入时还有一个 接口路径加上 basePath 的开关,Swagger 的 /v2/api-docs 返回的响应中也有这个字段。默认为应用的 basePath (ApplicationBasePath),若未设置应用基础路径的话就是默认值 /

大多数微服务的方案中都不会修改默认的 basePath ,而是在网关中设置对应服务的路由。比如用户服务的接口在网关中一般会设置一个 /user/** 的路由。

下面是设置 basePath 的示例代码[1]

java
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Value("${spring.application.name}")
    private String applicationName;

    @Autowired
    private ServletContext servletContext;

    @Bean
    public Docket createRestApi() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("博客服务") 
                .description("服务描述...")
                .version("1.0.0")
                .build();

        return new Docket(DocumentationType.SWAGGER_2)
                .pathMapping("/")
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("me.liujiajia.blog.user.controller"))
                .paths(PathSelectors.any())
                .build()
                .pathProvider(new RelativePathProvider(servletContext) {
                    @Override
                    public String getApplicationBasePath() {
                        return "/" + applicationName + super.getApplicationBasePath();
                    }
                });
    }
}

其中的 pathProvider 方法就是指定 basePath 字段值的处理。示例中将 basePath 指定为当前服务的名称。

假设用户服务下有一个接口 /login ,应用名称为 user ,网关中也将路由设置为 /user/** 。则在当前服务中其路由为 /login ,通过 Swagger UI 页面和网关访问时路由则为 /user/login

在 ApiFox 中导入若开启了 接口路径加上 basePath 开关,导入的接口也会自动变成 /user/login 。这种方案可以保证从同一个网关中导入的各种服务 API 定义之间不会发生接口重复的情况。

这种方案好处是在 ApiFox 中对于同一个网关来说,每个环境只需要设置一个服务前置 URL(也就是网关的 URL 地址)就可以了。

坏处是若修改了网关路由配置,所有的接口文档都要重新导入。由于接口路径都变了,关联的测试用例也需要重新添加。

还有一个稍微不太方便的地方是本地开发环境的接口测试。不过这个可以采用添加配置项的方式解决:在本地启用时不修改 Swagger 的 basePath

总的来说不着急的话还是不建议修改 basePath ,等等 ApiFox 更新应该就没有这个问题了。


  1. Springboot 整合 Swagger2,修改 basePath ↩︎