什么是API编排?
随着前后端分离架构、微服务架构、中台战略、产业互联互通的实施必将产生大量的API服务,API将成为企业的数字化资产且API会越来越多, API服务之间的相互调用和依赖情况也随之越来越多和复杂。业务系统与业务系统之间、关联企业之间的API都相应存在大量的API相互调用和逻辑重组需求、 使用传统的编码方式已完全不能满足业务敏捷化交付的特性,可视化服务编排平台通过无代码化来统一编排和调度API服务,通过可视化的拖、拉、拽可大幅提升API服务的敏捷化交付能力。
服务编排/数据聚合指的是可以通过一个请求来依次调用多个微服务,并对每个服务的返回结果做数据处理,最终整合成一个大的结果返回给前端。
例如一个服务是"查询用户预定的酒店",前端仅需要传一个订单ID,后端会返回整个订单的信息,包括用户信息、酒店信息和房间信息等。
这个服务背后可能对应着以下几个操作:
- 请求订单详情,返回订单对应的用户ID、酒店ID、房间ID;
- 根据各类ID查询对应的信息;
- 将数据做过滤、移动等操作,最后整合起来;
- 将整合好的数据返回给前端。
适用业务场景
- 作为业务中台、数据中台的API能力复用及融合层支撑前端业务创新
- 作为原子服务与前台应用的中间服务聚合层
- 通过API的编排实现多个异构业务系统数据的分发与汇聚
- 通过API的编排打通云上SaaS与私有端业务系统
- 作为企业大量的API服务与服务之间的逻辑重组平台
- 解决系统服务之间相互藕合的问题,服务的逻辑统一到编排层
技术选型
前端组件:
前端的可视化流程编排框架有很多,我因为没做过前端,这里只是看 LogicFlow 能实现咱们的需求,开发时有经验的同事可以选择一个最优的前端框架。
- LogicFlow :滴滴开源的可视化流程编排框架
后端组件:
- LiteFlow :规则引擎流程编排框架
- JSONPath:从JSON中提取数据的查询语言
- AviatorScript:表达式语言
LogicFlow可视化流程编排
LogicFlow在可视化API编排系统中用来实现页面中组件的拖拉拽,维护每个组件的信息(接口、参数、返回格式等),如上面图形的确认订单流程。
LogicFlow是一个基于JavaScript的可视化流程编排框架,用于快速构建流程图编辑器和流程执行引擎。
滴滴因为各业务系统虽然都需要应用流程可视化技术,但需求各不相同。有的对流程图的要求比较简单,图的数据格式也简单,而有的需要按照 BPMN 的规范来绘制流程图,对于定制化的要求较高。他们调研了市面上相关的框架 (BPMN.js、X6、Jsplumb、G6-editor),均存在不满足的场景,技术栈统一的成本很高。具体表现在:
- BMPN.js、Jsplumb 的拓展能力不足,自定义节点支持成本很高;只能全量引入,各系统无法按需引入
- 与后端配套的流程引擎适配,成本较高。均不支持数据转换、不支持流程的校验等业务定制需求。
因此,他们在 2020 上半年自研了 LogicFlow,支持各系统的流程可视化需求。
下图为通过LogicFlow实现的确认订单流程(仅实现图形展示,没有后台实现)
LiteFlow流程编排
LiteFlow在可视化API编排系统中用来实现后台接口的编排,由于LiteFlow只支持应用内部流程(本地方法)的编排,不支持远程api的编排,所以需要把Api调用的逻辑封装到LiteFlow提供的组件中,利用框架本身提供的组件和编排规则表达式的特性实现Api的编排。
LiteFlow是一种轻量级的规则引擎,用于组件式的编排和执行业务流程。它提供了一种简单而灵活的方式来定义、管理和执行复杂的业务逻辑。
LiteFlow的主要特点包括:
- 规则定义:通过定义规则和条件,可以实现对业务流程和组件之间的顺序和依赖关系进行编排和控制。
- 组件执行:支持定义和执行具体的组件操作,比如调用API、处理数据、触发事件等。每个组件可以有输入参数和输出结果。
- 条件和判断:可以设置条件和判断语句,用于决策流程走向或控制条件下的组件执行。
- 异常处理:支持定义和处理异常情况,比如错误发生时的回退处理、异常数据的过滤等。
- 数据共享:可以在组件之间共享数据,通过上下文对象或变量来传递和存储数据。
- 可扩展性:LiteFlow支持扩展和自定义组件,开发人员可以根据实际需求自定义组件的行为和逻辑。
使用LiteFlow可以将复杂的业务逻辑分解为可组合的组件,通过规则引擎进行执行和控制。它有助于提高业务逻辑的可读性、可维护性和灵活性,使得系统更易于扩展和调整。
在应用开发中,LiteFlow可以被广泛应用于工作流程管理、业务流程编排、决策引擎等场景。它为开发人员提供了一种简单而强大的方式来组织和管理复杂的业务逻辑,帮助提高开发效率和系统可靠性。
下图是把瀑布流模式代码,通过 LiteFlow 框架进行编排,把原有代码分解成 a b s d 四个组件,通过表达式THEN(a,b,s,d)进行编排,表达式可以在运行时动态加载,根据业务变化实时调整。
如表达式 THEN(a,b,s,d) 表示顺序执行,将表达式改为 WHEN(a,b,s,d) 则变为并行执行。如果业务变化要去掉 s 组件,则表达式修改为 THEN(a,b,d) 即可。同时LiteFlow还支持使用脚本定义组件。
实现复杂流程编排
JSONPath提取数据
JSONPath是一种用于从JSON数据结构中提取数据的查询语言。它类似于XPath对于XML的作用,可以根据特定的模式来定位和提取JSON中的数据。
JSONPath使用一种简洁而强大的语法来描述数据的路径和条件,使得在复杂的JSON结构中查找和操作数据变得更加方便和灵活。
以下是一些常用的JSONPath语法示例:
- $:表示根路径,用于定位JSON的根节点。
- .:点表示法,用于访问对象属性。
- []:用于访问数组元素,可以使用索引或通配符来匹配多个元素。
- *:通配符,可以匹配任意的属性名或数组元素。
- ..length`:用于获取数组的长度。
- ..:递归下降符,用于在嵌套的结构中查找匹配的元素。
- [?]:过滤器,用于根据条件过滤元素。
- @:当前节点,可以用于引用当前节点,如$.store.book[?(@.price < 10)]表示查找价格低于10的书籍。
通过在JSONPath中使用上述语法,可以实现从复杂的JSON结构中提取指定的数据,例如获取对象属性值、遍历数组元素、过滤数据等操作。
JSONPath在开发Web应用、数据处理、API集成等场景中非常有用,它提供了一种灵活而简单的方式来处理和查询JSON数据。
可视化api编排中使用JSONPath的目的:从上下文中(其它api的返回结果)获取数据作为当前接口的参数,或者组织流程的返回结果。
以下面的例子对JSONPash的使用进行说明。
如商品管理功能需要调用获取商品详情(getSkuInfo)和获取商品库存(getSkuStorage)的接口,每个接口的调用定义为组件,编排接口的入参是orgCode商城、shopId店铺ID、barcode条码
组件getSkuInfo接口参数:orgCode商城、shopId店铺ID、barcode条码
组件getSkuStorage接口参数:orgCode商城、shopId店铺ID、godsId商品ID
数据上下文:每个组件都能获取上下文数据,数据上下文格式定义成
json
{
"组件Id1":"组件Id1接口返回json",
"组件Id2":"组件Id2接口返回json",
"START":"编排流程的入参json"
}
那么该流程的初始上下文为:
json
{
"START":{
"orgCode":"11610201",
"shopId":"jingdong",
"barcode":"6932873820857"
}
}
组件getSkuInfo接口参数使用jsonPath定义如下:orgCode= <math xmlns="http://www.w3.org/1998/Math/MathML"> . S T A R T . o r g C o d e 、 s h o p I d = .START.orgCode、shopId= </math>.START.orgCode、shopId=.START.shopId、barcode=$.START.barcode
组件getSkuInfo执行完,数据上下文为:
json
{
"getSkuInfo":{
"code":200,
"message":"成功",
"data":**{
"barcode":"6932873820857",
"godsName":"可口可乐",
"godsId":"123456"
}
},
"START":{
"orgCode":"11610201",
"shopId":"jingdong",
"barcode":"6932873820857"
}
}
AviatorScript脚本语言
AviatorScript是一种强大的表达式语言,它为Java开发人员提供了轻量级和高性能的表达式求值引擎。AviatorScript的设计目标是提供一种简洁、安全和易于集成的表达式语言,用于处理数学计算、数据转换、逻辑判断等运算。
可视化接口编排使用AviatorScript的目的:
-
- 编写函数,并将函数关联至API,使得函数可以作为API的过滤器使用,对API的请求参数或返回结果进行加工处理
- 接口参数由Java中工具类生成时,可用表达式获取,如日期、时间戳、会话中的值UserId等,如日期定义成下拉框供用户选择,下拉列表显示yyyymmdd、到秒的时间戳等,然后跟脚本语言映射DateUtils.getCurrentDate()
- 脚本语言定义成编排流程中的组件,处理复杂的数据转换
- 实现LiteFlow的条件组件和选择组件,条件组件返回true和false;选择组件返回要执行的组件ID
动态注册接口
通过动态注册接口为可视化编排后的流程指定一个url,通过该url访问编排接口。
在Spring Boot中,RequestMappingHandlerMapping是Spring MVC框架中的一个重要组件,用于将请求映射到对应的处理器方法。
RequestMappingHandlerMapping的主要作用是根据请求的URL路径、请求方法和其他条件,将请求映射到合适的控制器方法进行处理。它负责解析和匹配请求路径、请求方法、请求参数、请求头等信息,并根据配置的映射规则来确定哪个控制器方法应该处理该请求。
java
// 注册接口
RequestMappingInfo mappingInfo = RequestMappingInfo .paths(ruleInfo.getUrlPath()) .build();
try {
Method method = null;
if (Boolean.valueOf(ruleInfo.getHasRequestBody())){
method = LiteflowController.class.getMethod("execute", HttpServletRequest.class, JSONObject.class);
} else {
method = LiteflowController.class.getMethod("execute", HttpServletRequest.class);
}
requestMappingHandlerMapping.registerMapping(mappingInfo, "liteflowController", method);
} catch (NoSuchMethodException e) {
logger.error("com.***.linkupapi.liteflow.node.NodeConfig.init注册接口异常", e);
}