graphql查询方案优化
起因
graphql API对外提供完整的接口文档,按需取数据的功能,对于接口联调和前端开发同学看来绝对是神器,但对于初看graphql的后台同学看来,这个取数据怎么取?对于一个两层结构的列表数据,我对列表中的每一项都取一次二级数据?这后台抗得住吗?
举个例子:我们有这样一个应用场景,我们要取一个用户列表,列表中每一项展示有3个字段id、name、friends,friends字段是一个数组,结果集中要做二层展开,展开成id、name,结果集如下:
{
"data": {
"userList": [
{
"id": "1",
"name": "Dan",
"friends": [
{
"id": "2",
"name": "Marie"
},
{
"id": "3",
"name": "Jessie"
}
]
},
{
"id": "2",
"name": "Marie",
"friends": [
{
"id": "1",
"name": "Dan"
}
]
},
{
"id": "3",
"name": "Jessie",
"friends": [
{
"id": "1",
"name": "Dan"
}
]
}
]
}
}
DB中数据结构如下,我们这里使用json文件存储数据,
用户信息表
{
"1": {
"id": "1",
"name": "Dan"
},
"2": {
"id": "2",
"name": "Marie"
},
"3": {
"id": "3",
"name": "Jessie"
}
}
用户关系表
{
"1":[
2,
3
],
"2":[
1
],
"3":[
1
]
}
DB层对外提供fakeDB.getAll获取用户列表接口,fakeDB.getFriendsInfo获取用户朋友信息接口,HTTP层再做一层封装,对外提供userBiz.getAll获取用户列表接口,userBiz.getFriendsInfo获取用户朋友信息接口,这样graphql中阶层获取数据请求数据的方式是先调用userBiz.getAll接口获取用户列表,再依次对每个用户调用一遍userBiz.getFriendsInfo接口获取列表每一项的friends字段,日志输出结果如下:
get all
get friends info1
get friends info2
get friends info3
这样列表项有多少项,就需要发起多少个userBiz.getFriendsInfo接口的HTTP调用,如果返回数据列表项再加大,数据层级再加深,HTTP调用的数量将会变得非常大,有没有办法减少HTTP调用呢,graphql实际上已经提供了解决方案
解决方案
graphql引入dataloader组件,提供合并请求的能力,dataloader的原理很简单,他利用nodejs的next tick机制,需要额外后台额外增加一个批量获取用户朋友信息的HTTP接口,修改graphql的schema,使其使用dataloader的方式,dataloader的具体配置详见附件代码,日志输出结果如下:
get all
get batch friends info 1,2,3
可见对列表项中的每一项获取friends信息合并成了一个HTTP请求
总结
这里假设的场景是一个graphql中间层调用HTTP接口的合并,如果使用graphql作为server端接口标准,同样可以使用dataloader合并sql层的访问