将多个Swagger API文档整合到一个“事实来源”文档中,以使开发人员能够更方便地利用API。
服务开发人员普遍存在一个问题,尤其是在微服务环境中,该问题可以描述如下。
The Problem
“陈述明确的问题是解决了一半的问题”-查尔斯·凯特林
想象一下,一组软件工程师正在开发一组微服务。 从最终用户的角度来看,前端开发人员正忙于照顾美观和可用性,他们需要知道如何将应用程序与API连接起来才能满足他们的需求,从而满足最终用户的需求。 , 要求。
如果我有多个微服务并且希望将端点记录在一个地方怎么办? 例如,为方便前端开发人员。 在这种情况下,第三方文档实现是Swagger UI。 在文献回顾期间发现的解决该问题的大多数尝试都取决于swagger-ui.html主页上下拉菜单的Swagger-UI提供的功能。 该解决方案意味着用户需要手动访问每个草签文档才能找到合适的服务。
Fig. 1.1 That label ‘Consolidated’, defaults to ‘Default’; it has been changed inside the source code. It is this dropdown that is used to control which of the APIs to view documentation for, in other solutions for this problem.
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. Although elegant, it was felt that it was overkill to have a Eureka instance, solely for this purpose, and a consumer would lack a holistic view of all the services at their disposal.
Ťhis is another example that, although is without a third-party service discovery implementation, leaves us with the necessity to manually select and investigate, each end-point individually.
在此解决方案中,开发人员无需使用第三方服务发现工具,而只需配置所需的端点即可。 这是我想到的一个选择,这使我有信心继续我的打算。
A Solution
“解决方案通常比难题更漂亮。” –理查德·道金斯
该解决方案是一个Spring-boot应用程序,它同时还使用Springfox,可整合所有已配置的端点(内部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的标准,文档编制过程期望描述每个端点的Json出现在已配置的url(+‘/ v2 / api-doc’)。 还有两个注意事项。
以下内容至少指的是Swagger版本2.x。 必须将Json硬编码为Strings才能在“ / swagger-resources / configuration / ui”和“ / swagger-resources”。 Chrome开发工具在同事的帮助下帮助我实现了这一目标。 稍后将在组态部分。
还必须在以下位置提供针对我们API的杰森‘/ v2 / api-docs’,因此有必要提供一个控制者以上请求映射返回了合并杰森所有要记录的API的表示形式,这使我进入实现的第二部分。
招摇的巩固杰森实现如下:Google的GSON用于生成地图个人的杰森每个API文档的表示形式。
下一步是将它们合并为一个地图,其中包含所有数据。地图s就像您将看到的那样,非常适合合并。 开发人员可以使用他们选择的任何方式来达成合并地图表示。 例如,这将达到目的:创建一个名为原版的,这是一个地图等于第一个地图,在列表中地图s进行合并,将其传递给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 Map && original.get(key) instanceof Map) {
Map originalChild = (Map) original.get(key);
Map newChild = (Map) 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返回自己的地图 implementation to represent Json key-value pairs, this allows recursion to be used, as above, to merge all 地图s into one 超级地图,然后再次使用Google的GSON将其转换回Json以进行显示,就好像它是Swagger UI呈现的单个API一样。 这些将按字母顺序显示,并按API分组。
Configuration
此整合式摆幅弹簧启动应用程序的配置在内部处理application.yml。 此配置部分主要参考Swagger-UI的配置。
在RequestMapping返回的Json“ / swagger-resources / configuration / ui”除其他外,还包含一个'filter'标志,尽管该标志的值为布尔值,但默认为true。
我利用这次机会删除了该属性,因此接受默认设置,因为可能有大量的整合API可供搜索。 为了正确显示Swagger文档,唯一需要的属性是“ supportedSubmitMethods”,即使这样,默认情况下所有 when it is set to an empty List. I have explicitly added 所有 methods, for documentation purposes.
// /swagger-resources/configuration/ui
uiConfigurationMap.put("supportedSubmitMethods", Arrays.asList(
"get",
"put",
"post",
"delete",
"options",
"head",
"patch",
"trace"
));
我应该强调上述配置(或缺少配置)“过滤器”。 取决于其他合并工作中看到的下拉列表,此处提供的过滤功能为这种合并方法提供了有力的依据。
除了上述配置之外,还有机会更改最终文档中出现的某些静态值,这实际上是通过覆盖位于路径“/swagger-resources或由其返回的Json来实现的””,这也是硬编码。在上述配置的硬编码的两种情况下,都使用以下软件编码模式:例如“受保护的静态”字符串swagger资源,已声明。注意,这不是最终的;这是因为稍后将其设置为等于jsonized地图,populatedinsideastaticblock,andlaterreturnedbyacustomcontroller.
// /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的分号分隔列表。 首先编译此列表,并将其作为列表放在合并后的列表中。地图,键为“ 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合并,用户利用过滤器功能取得了显着效果。
Fig1.2 A screenshot of the homepage, with filtering enabled.
Dependencies
为了使其能够编译,将需要Java 12。
在pom.xml中,我声明了note的以下依赖项。
春狐 这允许Spring和Swagger之间的相互作用。
io.springfox
springfox-swagger-ui
2.9.2
Google的GSON 这用于解组json字符串,然后重新编组合并的字符串地图回到合并的Json String。
com.google.code.gson
gson
1.4
Summary of Process
为用户提供一种机制,以配置要合并的API的URL。
获取每个目标API的Json; 接下来我们将每个Json字符串转换为地图实施,然后我们合并那些地图s。 最后,我们将合并后的地图交给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
有离线模式; 假设至少进行了一次在线尝试,此后杰森在该在线尝试期间捕获的内容将用于以后的尝试,当然,除非该尝试是在网上进行的,在这种情况下,它会像往常一样进行。
此功能有明确的用例,可通过简单的文件I / O实现。
Open Source
This tool is available to use, subject to the open source license agreement; and can be cloned from here: https://github.com/eon-com/swagger-together.git
不用说,该应用程序将合并任何一组API昂首阔步文档,而不仅仅是Java。