在上一节,我们初步了解了API步骤区域的功能,本章我们来逐个详解所有步骤类型,在了解所有类型后,相信你可以通过组合所有不同的步骤,来开发出各种各样的应用,提供给用户完善的产品功能。
通用部分
如图所示:
点击添加步骤可以增加一个步骤卡片,步骤卡片的右下角有两个按钮,左侧为在该步骤前添加一个新步骤,右侧为删除该步骤。
在编辑之前首先输入步骤ID以便区分不同步骤,再选择不同的步骤类型。
此处的步骤ID将在后续使用,用于步骤之间的某些值来源互相引用。
值来源详解
在步骤中,我们需要设置一些实际处理的值,这些值肯定不能全部写死在控制台界面,它是活的数据,所以会由值来源这个选项和值去确定实际的数据来自哪里。
我们以create动作为例,值来源有这些:
将值来源选为API参数并设置值为postId时,就表示会用请求参数的postId数据去查询文章。模拟请求如下:
{"body":{"appId":"example","api":"test","version":"v1","args":{"postId":}}}
该步骤实际执行中就会查询一篇ID是的文章。
前序步骤能够引用前面步骤的返回数据:
如此处,引用了前面的someStep步骤的data值。假设someStep步骤的结果数据如下:
{"data":,"other":"xxx"}
那么该步骤实际执行中就会查询一篇ID是的文章。
另外,API参数和前序步骤两个来源都能用Json选择器去选择实际值。在后面的值文本框中输入以$开头的表达式,就可以用表达式语法选择JSON数据的值。
假设某个值来源的数据格式如下:
{"data":,"other":[{"a1":1},{"a1":2}]}
此时在值文本框中填写$.other[1].a1就会在实际执行中得到2。你可以在此处Demo中实际测试。
同理,Token数据来自于用户token解析后的数据对象。
固定设置则是直接用此处填写的值:
表示该步骤实际执行中就会查询一篇ID是的文章。
随机id则会生成一个随机值,会默认生成21个字符组成的值,例如:yorhcDIFv2V-KyKE5YRa6。
而在后面的值文本框中填写数字10时,这个随机值会生成10个字符组成的值如yorhcDIFv2。值决定了随机值的长度。
时间戳是该步骤实际执行时的linux时间戳,格式为1622865883,如果在后面的值文本框中输入或-则会将执行时的时间戳加1秒或减1秒,以此类推。
唯一微秒是A系列引擎执行数据库create动作时才会用到的,意思是自动生成微秒ID。
另外还有数据库getMany动作下才有的两个选项:无限大和无限小即getMany的范围,当后面的值文本框中有设置时,将优先采用值来源为API参数的效果,没有该API参数时会回退到无限数。
云数据库
该步骤的很多名词和功能解释在云数据库章节,需要提前阅读。
首先是最核心的云数据库类型,当我们选择步骤类型为云数据库后,会显示类似如下界面:
要求继续选择应用、表、动作和是否并行。
应用可以选择当前组织所有已安装的应用,表可以选择选择应用的所有数据表。
发现了没有,得益于该设计的灵活性,开发者可以将多个应用结合起来,或是对别的应用进行补充开发。
比如“用户系统”原应用没有提供根据昵称搜索用户的API,但是我们完全可以做一个补充应用,设计对“用户系统”的User表进行昵称搜索的API。这样所有应用都互通了。当用户安装你的应用同时也会安装所有你在API中调用了的所有其他应用。
积木式的应用开发使得我们能够通过多个应用的组合轻松完成一个大型的复杂应用,同时还保持足够的灵活性。
通用部分
返回值
在getgetManysearch中,有一个共同的选项为返回数据列,可以勾选本查询需要返回的数据列。因为有些时候不需要查全部的数据,全选可能会包括到一些不希望返回给前端的数据,比如隐私数据会泄露用户隐私,长文本数据会影响查询速度等。默认是全部返回。
选择列
在createupdate中,有一个共同的选项为选择数据列,可以选择在本步骤中新建或更新该条数据时需要用到的部分列。因为有时候单个API并不需要涉及到全部数据列的变更,所以选择后会更简洁。
另外,不管是选择了部分列还是全部列,只会变更有值的列,比如说logo的值来源是API参数,但是某个请求的API参数中没有logo或者为空字符串,那么并不会更新该项,也不会将原先在数据库已经有的logo值变为空。
条件
在createupdatedelete中,有一个共同的选项为条件,可以选择在本步骤中执行数据库动作时的前置条件。
条件有三个:
忽略:不管该主键值的数据是否存在,都会执行。如果有原数据,那么create会覆盖原数据,如果没有原数据,那么update会新建数据。
期待存在:期待符合该主键值的数据存在,如果没有该数据,那么都会报错Conditioncheckfailed。通常用于更新和删除希望已存在的值。
期待不存在:期待符合该主键值的数据不存在,如果该数据存在,那么都会报错Conditioncheckfailed。通常用于新建数据时防止覆盖已有数据。注意,主键值来源为随机id和唯一微秒时不要选择该项。
接下来我们要选择动作。
动作有以下几种:
get查询单条数据
getMany查询多条数据
create新增数据
update修改数据
delete删除数据
search搜索数据(仅S系列引擎)
简单易懂,就是所谓的数据库增删改查。
并行则是根据某个数组并行执行上述动作。
我们继续拿“简易博客”应用中的Post文章表来举例。
get
选择get后如图所示:
下方为主键区域,为主键选择值来源并设置值后就可查询该参数的数据。
步骤返回格式:
{"步骤id":{"id1":"a","id2":"b","data1":"c","data2":"d"}}
getMany
选择getMany,此处我们用双主键的表“组织分组”作为示例,如图所示:
这时候会看到和前面的get不同,出现了两个主键区域。
首先我们要理解,getMany是查询多条数据,那么肯定是要给定一个查询范围的,所以第一个主键区域确定查询的开始位置,第二个主键区域(会标注:末序主键)确定查询结束的位置。默认是按照字符表排序。
可以选择排序方式,正序就是12或az这样,倒序就是反过来21主键大的排前面。
比如说有如下一些“组织分组”数据:
[{"orgId":"qinglincloud","groupId":"a"},{"orgId":"qinglincloud","groupId":"b"},{"orgId":"other","groupId":"a"}]
开始排列组合查询方式示例:
设置查询起始主键的值为orgId=无限大,groupId=无限大,结束主键的值为orgId=无限小,groupId=无限小,排序为倒序,因为字符表顺序为oqab那么获得下列顺序:
[{"orgId":"qinglincloud","groupId":"b"},{"orgId":"qinglincloud","groupId":"a"},{"orgId":"other","groupId":"a"}]
设置查询起始主键的值为orgId=无限小,groupId=无限小,结束主键的值为orgId=无限大,groupId=无限大,排序为正序,因为字符表顺序为oqab那么获得下列顺序:
[{"orgId":"other","groupId":"a"},{"orgId":"qinglincloud","groupId":"a"},{"orgId":"qinglincloud","groupId":"b"}]
如果指定前面的主键,那么只会查询指定范围:
设置查询起始主键的值为orgId=qinglincloud,groupId=无限大,结束主键的值为orgId=qinglincloud,groupId=无限小,排序为倒序,因为字符表顺序为ab那么获得下列顺序:
[{"orgId":"qinglincloud","groupId":"b"},{"orgId":"qinglincloud","groupId":"a"}]
然后给范围设定值:
设置查询起始主键的值为orgId=qinglincloud,groupId=b,结束主键的值为orgId=qinglincloud,groupId=a,排序为倒序,此时我们要注意,范围查询是左闭右开区间,也就是说,起始范围的值如存在则会包含,结束范围的值不管有没有都不包含。获得下列数据:
[{"orgId":"qinglincloud","groupId":"b"}]
另外要注意,选择排序为倒序时,起始值一定要比结束值大,选择排序为正序时,起始值一定要比结束值小。
范围查询默认查询行,最大查询行或者3MB大小的数据(整个API所有返回数据不得大于5MB)。查询的数量由查询行数来源和行数值确定。你可以设置来源为API参数,行数值为postsLimit,这样查询行数就是API参数中的postsLimit项的值。
最后还有一个添加过滤条件功能:
条件运算符有这些:=!===作用如同符号。
可以过滤查询结果,如上图所示,就会过滤掉groupId不等于a的数据。
可以有多个过滤条件。
注意过滤是在查询之后进行,即假如查询行数值设置为固定值,就会先查行数据出来,然后过滤成行,最后也只有行返回,并不包含这行后面符合过滤条件的数据,如需查询更多,此时你可以使用返回的nextId再查询后面的数据。
C系列引擎还会有镜像表选项,具体请查看云数据库文档。
步骤返回格式:
{"步骤id":{"data":[{"id1":"a","id2":"b","data1":"c","data2":"d"}],"nextId":{"id1":"a2","id2":"b2"}//无则为null}}
create
选择create后如图所示:
基本各部分作用前面已有介绍。
步骤返回格式:
{"步骤id":{"id1":"a","id2":"b"}}
update
选择update后如图所示:
多了一个选项为更新类型,有三种:
更新:基本和create相同。
递增:只能选择int类型的数据列,更新值同样为整数数字,将会原子式递增或递减。
删除:选择数据列确定要删除的列数据,值来源和值都可以忽略。
注意此处递增选项,非常有用。假设有一个比较常见的场景,帖子点赞:
在传统数据库中,常用的做法是先查询得到该条帖子的点赞数,然后加1,再将更新数字写入进数据库。
但是如果该帖子很火,有很多人同时点赞,那么在分布式的情况下,多个服务同时查询帖子点赞数得到值为10,加1后为11,再同时写入数据库,结果多个点赞同时进行的情况下只会最终+1,甚至有个别服务比较慢,还会出现回退。所以不得不使用数据库事务,锁住数据库后查询、加1更新后解锁。有非常严重的性能问题。
Redis等数据库就做了个功能是原子递增,即不管同时有多少并发,不需要先查后更新,直接给数据库一个递增值,数据库层面就完成了数字更新。分布式服务只需要发送递增值就行了,返回给它递增后的数据。完美解决上面的问题。
此处的递增就是这样的实现。递增值可以为正整数也可以为负整数。
步骤返回格式:
{"步骤id":{"id1":"a"//如果是递增类型则返回的是递增项}}
delete
选择delete后如图所示:
基本和get一样。
步骤返回格式:
{"步骤id":{"success":true}}
search
search选项只在当前表为S引擎时出现,此处我们就用“用户系统”的User表做例子:
search的查询没有主键区域,因为主键和所有的列都可以查询,主要由搜索条件控制,添加多个搜索条件就会查询到符合多个条件的数据。
上面的例子是根据手机号查询用户,所以类型是精确查询。所有类型如下:
精确查询要求查询值和数据值完全相等。
匹配查询一般应用于全文检索场景,可应用于text类型。查询值能匹配到数据值其中一部分即可,数据值是分开的也可以。
短语匹配查询类似匹配查询,但查询值要完全匹配数据值的一部分。
范围查询类似getMany,只不过原先的主键范围也可以用于列范围。
前缀查询即查询值满足数据值的前缀即可。
相关性查询会计算查询值和数据值的相关性。
因子相关性则会额外加入一个因子参数来计算相关性。
嵌套查询则是查询nested类型数据。
通配符查询可以有*代指任意字符,?代指单个字符去查询数据。
总行数查询,只查符合条件的行数。
地理长方形查询类似地图APP,在一个长方形内查询相关数据。
地理距离查询是在查询经纬点距离内的经纬数据。
地理多边形就是将上面的长方形改为多边形。
多词精确查询是精确查询的数组形式。
列存在查询常用于确认某个列是否存在数据。
当然,在查询多条数据时,也可以添加排序类型,可以多个组合。
主键排序和getMany一致。
列排序也类似,只不过比较值成了数据列。
相关性查询适用于全文检索场景,使用了BM25算法计算相关性。
地理点排序适用于位置排序,比如“附近的人”这种场景。
其中很多查询条件可以由API参数决定,具体请查看API格式文档。
步骤返回格式:
{"步骤id":{"data":[{"data1":"c","data2":"d"}],"nextToken":"xxx"//用于翻页查询,无则为null}}
并行
并行选项意思是是否并行执行该步骤,并行需要一个数组来提供并行执行的数量和并行参数,我们以“组织系统”中的getManyUserOrgAPI为例:
这个步骤的前一个步骤getManyUserOrg查询到了所有该用户加入了的组织的信息,但因为这是一个中间表,没有组织的具体数据,只储存了orgId,那么我们就需要一个并行步骤来查询所有的相关组织。
这里数组来源于上个步骤的data数组,然后下方get动作中多了个值来源并行数组项,可以选择该值获取到本次并行执行时的值。
用前端代码来描述如下:
constlist=[1,2,3];//并行数组list.map((item)={//此处item就是并行数组项getData(item);//并行执行步骤});
步骤返回格式:
{"步骤id":[{"id1":"a","id2":"b","data1":"c","data2":"d"},{"id1":"a2","id2":"b2","data1":"c2","data2":"d2"}]}
条件判断
条件判断类似于if逻辑。
可以对左值和右值进行判断,符号的话有前端基础应该都懂,只不过=和!=是js中的===和!==。
得到判断结果后即可根据结果有不同的行为。
继续则会继续执行下面的步骤。
报错则会返回报错信息。
终止则会终止所有步骤并返回前面和当前的步骤数据。
执行步骤则会执行被选择的步骤,跳过没有被选择的步骤。
步骤返回格式:
{"步骤id":true//orfalse}
JS脚本
在某些场景,我们需要处理一些特殊的值,但是又不能放到前端处理,那么JS脚本步骤就派上用场了。
该步骤可以用JavaScript语言执行一些运算。
JS脚本有两种环境:JS环境和Node环境,第一种类似于在浏览器开发者工具Console中的体验,第二种是类似Nodejs环境中的体验。
直接举例,在“用户系统”中,有个API是创建手机短信验证码,这个逻辑很简单,但是我们不能在前端创建,不然就可能会被非法用户截取到,所以这里我们用该步骤如下:
因为逻辑非常简单,这里就用了第一种JS环境,该步骤的值就是code这个随机数。
那么第二种Node环境就比较适合复杂的计算或者需要nodejs库的步骤,比如同样在“