将多个Swagger API文档整合到一个“事实来源”文档中,以使开发人员能够更方便地利用API。
服务开发人员普遍存在一个问题,尤其是在微服务环境中,该问题可以描述如下。
The Problem
“陈述明确的问题是解决了一半的问题”-查尔斯·凯特林
想象一下,一组软件工程师正在开发一组微服务。 从最终用户的角度来看,前端开发人员正忙于照顾美观和可用性,他们需要知道如何将应用程序与API连接起来才能满足他们的需求,从而满足最终用户的需求。 , 要求。
如果我有多个微服务并且希望将端点记录在一个地方怎么办? 例如,为方便前端开发人员。 在这种情况下,第三方文档实现是Swagger UI。 在文献回顾期间发现的解决该问题的大多数尝试都取决于昂首阔步-ui。html主页上下拉菜单的Swagger-UI提供的功能。 该解决方案意味着用户需要手动访问每个草签文档才能找到合适的服务。
图. 1.1 That label ‘Consolidated’, defaults to ‘Default’; it has been changed inside the source code. 在此问题的其他解决方案中,正是此下拉列表用于控制要查看哪些API的API。.
Literature Review
在本节中,“ Google认证的Google”也许是更准确的标题,因此,在期望得到控制的情况下,我将继续进行。
如前所述,过去尝试解决此问题的方法是使用Swagger UI的主页右上角的下拉菜单功能,如上图所示,用于选择要查看其文档的API 。
Here is an example that sees a Eureka server being used to discover each service to be documented. Eureka is a service discovery tool; further information pertaining to Eureka servers can be found here. 尽管优雅,但仅出于此目的,有一个尤里卡实例是过高的,而且消费者将对所使用的所有服务缺乏整体看法.
This is another example that, although is without a third-party service discovery implementation, leaves us with the necessity to manu所有y select和investigate, each end-point individually.
在此解决方案中,开发人员无需使用第三方服务发现工具,而只需配置所需的端点即可。 这是我想到的一个选择,这使我有信心继续我的打算。
A Solution
“解决方案通常比难题更漂亮。” –理查德·道金斯
该解决方案是一个Spring-boot应用程序,它同时还使用春狐,可整合所有已配置的端点(内部application.yml
)放入一个单一的草签文档中。 配置相对简单:
endpoints: # a list of sample base urls, note, omit "/v2/api-docs"
- name: UnusedName_key
url: https://api_server1.eon.de
username: joe_bloggs
password: joe_bloggs_pa55w0rd!
- name: UnusedName2_key
url: https://api_server2.eon.de
username: joe_bloggs2
password: joe_bloggs2_pa55w0rd!
根据Swagger-UI的标准,文档编制过程期望描述每个端点的杰森出现在已配置的url(+‘/ v2 / api-doc’
)。 还有两个注意事项。
以下内容至少指的是Swagger版本2.x。 必须将杰森硬编码为Strings才能在“ / swagger-resources / configuration / ui”
and “ / swagger-resources”
。 Chrome开发工具在同事的帮助下帮助我实现了这一目标。 稍后将在组态部分。
还必须在以下位置提供针对我们API的杰森‘/ v2 / api-docs’
,因此有必要提供一个控制者
以上请求映射
返回了合并杰森
所有要记录的API的表示形式,这使我进入实现的第二部分。
招摇的巩固Json
实现如下:Google的GSON用于生成地图
个人的Json
每个API文档的表示形式。
下一步是将它们合并为一个地图
,其中包含所有数据。地图
就像您将看到的那样,非常适合合并。 开发人员可以使用他们选择的任何方式来达成合并地图
表示。 例如,这将达到目的:创建一个名为原版的
,这是一个地图
等于第一个地图
,在列表中地图
进行合并,将其传递给deepMerge功能
maps.forEach(map -> {
updateInfo(titles, map); // this has no effect in the merging process,
// rather it does work relating to the final
// title of the document
for (Object key : map.keySet()) {
if (map.get(key) instanceof 地图 && original.get(key) instanceof 地图) {
地图 originalChild = (地图) original.get(key);
地图 newChild = (地图) map.get(key);
original.put(key, deepMerge(List.of(originalChild, newChild)));
} else if (map.get(key) instanceof List && original.get(key) instanceof List) {
List originalChild = (List) original.get(key);
List newChild = (List) map.get(key);
for (Object each : newChild) {
if (!originalChild.contains(each)) {
originalChild.add(each);
}
}
} else {
original.put(key, map.get(key));
}
}
});
return original;
GSON返回自己的Map
表示Json键值对的实现,如上所述,这允许使用递归将所有Map合并为一个超级地图,然后再次使用Google的GSON将其转换回Json以进行显示,就好像它是Swagger UI呈现的单个API一样。 这些将按字母顺序显示,并按API分组。
Configuration
此整合式摆幅弹簧启动应用程序的配置在内部处理application.yml
。 此配置部分主要参考Swagger-UI的配置。
在RequestMapping返回的Json“ / swagger-resources / configuration / ui”除其他外,还包含一个'filter'标志,尽管该标志的值为布尔值,但默认为true。
我利用这次机会删除了该属性,因此接受默认设置,因为可能有大量的整合API可供搜索。 为了正确显示Swagger文档,唯一需要的属性是“ supportedSubmitMethods”,即使这样,默认情况下all设置为空列表时。 我已明确添加所有方法,以用于记录目的。
// /swagger-resources/configuration/ui
uiConfigurationMap.put("supportedSubmitMethods", Arrays.asList(
"get",
"put",
"post",
"delete",
"options",
"head",
"patch",
"trace"
));
我应该强调上述配置(或缺少配置)“过滤器”。 取决于其他合并工作中看到的下拉列表,此处提供的过滤功能为这种合并方法提供了有力的依据。
除了上述配置之外,还有机会更改最终文档中出现的某些静态值,这实际上是通过覆盖位于路径“ / swagger-resources或由其返回的Json来实现的” ”,这也是硬编码。 在上述配置的硬编码的两种情况下,都使用以下软件编码模式:例如“受保护的静态”字符串swagger资源,已声明。 注意,这不是最终的; 这是因为稍后将其设置为等于jsonized Map
,填充在静态块中,然后由自定义控制器返回。
// /swagger-resources
static {
Map<String, String> swaggerResourceMap = new LinkedTreeMap<>();
swaggerResourceMap.put("name", "Consolidated");
swaggerResourceMap.put("url", "/v2/api-docs");
swaggerResourceMap.put("swaggerVersion", "2.0");
swaggerResource = "[" + new Gson().toJson(swaggerResourceMap) + "]";
}
默认文档标题只是所有功能API的分号分隔列表。 首先编译此列表,并将其作为列表放在合并后的列表中。Map
,键为“ info”,(info.title)。 然后,此列表用于创建标题,如下所示:
map.get(INFO).put(TITLE, String.join(SEMICOLON, (Iterable<? extends CharSequence>) map.get(INFO).get(TITLE)))
此外,此标题是可配置的,方法是在application.yml
.
swagger-vars:
docTitle : 'Consolidated Doc, for example'
Finished Product
以下屏幕截图描绘了四个连接的API的醒目UI合并,用户利用过滤器功能取得了显着效果。
图。1.2 A screenshot of the homepage, with filtering enabled.
Dependencies
为了使其能够编译,将需要Java 12。
在pom.xml中,我声明了note的以下依赖项。
Springfox
这允许Spring和Swagger之间的相互作用。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Google的GSON
这用于解组json字符串,然后重新编组合并的字符串Map
回到合并的Json String。
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>1.4</version>
</dependency>
Summary of Process
为用户提供一种机制,以配置要合并的API的URL。
获取每个目标API的Json; 接下来我们将每个Json字符串转换为Map
实施,然后我们合并那些地图
。 最后,我们将合并后的Map
交给Json,并将该Json可供swaggerui显示。
同时,基于开发人员提供的注释,Springfox还将使其他Json可供Swagger-Ui使用。 我们仅创建用于管理该元数据编译的控制器。
Docker
Docker Hub上有一个可用的docker Image,包括一个spring boot应用程序,通过从该映像创建容器,您将看到此应用程序的有效示例,其中整合了4个API。
为了从该映像创建容器,您必须首先在本地计算机上安装docker。 然后,只需运行以下命令:
$> docker container run -p 80:8080 declantreanor/swaggerui:final
The app will then be viewable at the url http://localhost/swagger-ui.html
系统会提示您输入的用户名/密码为bob / bob。
Offline Mode
有离线模式; 假设至少进行了一次在线尝试,此后Json
在该在线尝试期间捕获的内容将用于以后的尝试,当然,除非该尝试是在网上进行的,在这种情况下,它会像往常一样进行。
此功能有明确的用例,可通过简单的文件I / O实现。
Open Source
根据开放源代码许可协议,可以使用此工具; 可以从这里克隆: https://github.com/eon-com/swagger-together.git
不用说,该应用程序将合并任何一组APIswagger文档,而不仅仅是Java。
from: https://dev.to//eon/how-to-consolidate-api-documentation-in-a-spring-boot-microservices-environment-dgd