上手Swagger30,踩了两个坑 踩坑前言 踩坑记录 结

踩坑前言

Swagger3.0出来一段时间了,虽然简化了基础的配置,但作为一个大版本的升级肯定存在不少问题,不少2.x版本的类都被标记为过时了,大部分类的构造与属性设置依旧都交给了对应的Buidler处理,但不少配置上都引入了函数式接口去处理,对于对函数式编程不太了解的开发者而言可能有一定的配置难度。目前国内较少对3.0版本的配置介绍,所以自己在项目里将Swagger升级到3.0后看了下替代了标记过时(@Deprecated)相应功能的源码进行相应的配置,结果踩了2个坑,所以分享下踩坑记录与3.0的通用配置方式。

踩坑记录

项目中使用了jwt鉴权,但无论对于开发人员还是测试人员来说每次Swagger测接口前都要登录获取token,每次传token都是一件很麻烦的事,所以我便打算按Swagger比较常用的全局参数设置将Authorization设为全局header并设置默认值,于是有了以下3.0(OAS_30指Open API Spefication 3.0)中的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
less复制代码@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.globalRequestParameters(Lists.newArrayList(
new RequestParameterBuilder()
.name("debug")
.description("ignore authorization")
.in(ParameterType.HEADER)
// 类内部创建了默认的builder以供属性设置
.query(parameterSpecificationBuilder -> parameterSpecificationBuilder.defaultValue("1")
.allowEmptyValue(true))
.build(),
new RequestParameterBuilder()
.name("Authorization")
.description("token")
.query(parameterSpecificationBuilder -> parameterSpecificationBuilder.defaultValue("1")
.allowEmptyValue(true))
.in(ParameterType.HEADER)
.build()
))
.select()
.paths(PathSelectors.regex("^(?!/error).*"))
.build();
}

以上配置中的query()可以看成是Swagger3.0中配置风格的一个核心:在配置类中创建好相应的属性对象builder,并暴露一个该builder的Conumser函数式接口作为参数的方法,开发者根据需要提供一个Consumer进行对该builder的操作(属性设置),只要了解了该风格相信基本上新版本的配置看看源码也能很快上手。

以上配置代码query()方法中我取了RequestParameterBuilder类中的属性对象simpleParameterBuilder引用进行了属性设置,RequestParameterBuilder部分源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typescript复制代码public class RequestParameterBuilder {
......
SimpleParameterSpecificationBuilder simpleParameterBuilder;

......

private SimpleParameterSpecificationBuilder queryBuilder() {
if (simpleParameterBuilder == null) {
simpleParameterBuilder = new SimpleParameterSpecificationBuilder();
}
return simpleParameterBuilder;
}

public RequestParameterBuilder query(@NonNull Consumer<SimpleParameterSpecificationBuilder> parameter) {
parameter.accept(queryBuilder());
return this;
}

......

其实个人认为既然集成SpringBoot了以properties类为主导进行属性设置而非Builder与FunctionalInterface对开发者使用而言会更便利,现在先踩坑填坑。按照对2.x的版本配置与了解个人以为以上的配置应该是没有问题的,然而居然出现了2个坑。

坑A:name为Authorization的全局header参数值将无法传到后端

当我添加一个Authorization的全局header的时候测试时发现怎么传都没有传到后端,一开始以为是Swagger的bug,但考虑到这个name的敏感性,我就去翻了下OpenAPI 3.0(Swagger 3.0是按照OpenAPI 3.0的规范去设计实现的,文档的数据格式也是遵循3.0规范),于是翻出了以下内容:
parameter-object-doc
当全局header参数中包含命名为AccpetContent-TypeAuthorization的参数时,参数的定义将被忽略。于是我加了一个非忽略header,得到了以下结果:

swagger-authorization-header

可以看到全局header设置中debug是能接收到的,而Authorization是被忽略的,即基本确认非bug,只是我没有看规范而已。既然以该方式定义的Authorization header无法被接收,但Swagger以往的版本还有一种设置全局token的方式-SecurityContextSecurityReference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
less复制代码@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.securityContexts(Arrays.asList(SecurityContext.builder()
.securityReferences(Arrays.asList(SecurityReference.builder()
.reference("Authorization")
.scopes(new AuthorizationScope[]{new AuthorizationScope("global", "accessEverything")})
.build()))
.build()))
.securitySchemes(Arrays.asList(new ApiKey("Authorization", "Authorization", "header")))
.select()
.paths(PathSelectors.regex("^(?!/error).*"))
.build();
}

SecurityContextSecurityReference的设置与以往版本变化不大,结果也达到了个人的期望(后端能获取到Authorization header),只是该方式配置的header无法设置默认值而已,效果图如下:
Swagger-Security

坑B:全局参数的默认值并没有起效

虽然通过query()方法设置了参数默认值,但实质上Swagger并没有把该默认值设置到页面上,从坑1中的演示图1可以看到全局参数即使设置了初始值1,但页面上还是空的。该坑确认了是3.0的bug,在github里也找到了相应的issue,该bug已加到了3.0.1的里程碑中(即3.0.1版本会修复):

结语

虽然官方框架的使用更具有普遍性,但目前还是觉得自己写的香,如果以上3.0版本出现的问题会影响当前项目的测试使用则不建议先升级,玩玩尚可。
personal-swagger

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%