GraphQL 是 Facebook 出品的一个服务查询语言(https://github.com/facebook/graphql)
一个GraphQL查询是个字符串,查询引擎接收这个字符串之后返回所需要的数据。原生的 GraphQL,查询是返回一个 JSON 数据。
前端/移动端
传统的 RESTful 或 RPC 等形式请求远程服务器数据时,通常需要服务端 和 前端/移动端,共同约定好数据格式的要求,然后封装成对应的 Bean。前端/移动端,在请求服务端时,服务端就会按照约定的格式返回数据。
这种情况下任何一个前端,获取数据方面的需求。都会要求服务端进行配合,而服务端又不能简单的偷懒把所有数据都透传给前面。因此看似一个简单的多返回一个字段的需求,都要等后端排期发版。
不光如此,由于后段数据接口在最初约定完毕之后,通常数据结构服务端是不会在投入过多人力成本协助前端/移动端进行技术改造。这时有限的服务端人力资源会被投入到更重要的需求中去。
久而久之,前端/移动端/服务端 三者开始背负历史包袱。
GraphQL 是解决局面的一个利器,服务端可以编写接口方法,将服务注册到 GraphQL 引擎中。前端/移动端 同学可以通过 GraphQL 随意组织索取自己想要的数据,再也不必受到 服务端 的制约。
从而实现了 API 和 数据模型的解耦,加快了 前端/移动端/服务端 各自的迭代步伐。
服务端
即便是 前端/移动端 依然通过传统的 API 约定 数据模型的方式请求数据。在服务端的程序中 开发者也需要 从 DAO/RPC 中查询数据,然后组织成需要的结果。
每当产生一个数据查询都要组织一次数据,通常我们是以 MVC 方式在 Action 或者类似的其它地方。中编写代码从各种 Service 中查询数据,然后组织成页面需要的 VO 对象。
使用 GraphQL 的思想同样的可以让您在 服务端 内部享受到。API 和 数据模型 解耦带来的好处。
但是可惜的是目前官方 Facebook 提供出来的 GraphQL 版本,显然是强调解决 “前端/移动端/服务端” 三者之间的 API 和数据模型解耦问题。虽然有一些公司,例如:阿里,在服务端中可以纯粹形式利用 GraphQL 的进行 应用和应用之间的解耦。但是其复杂性依然不是一个简单的 jar 包或者框架可以解决的。
因此 Simple GraphQL 应运而生。
Simple GraphQL
如名所示,Simple GraphQL 是对 Facebook 的 GraphQL 进行的一些裁剪。使其更加容易被开发者所接受,先简单展示一下它的语法特性。首先我们调用 userManager 类的 findUserByID 方法传递一个 userID 参数查询 UserInfo,然后在返回所需要的 name、age、nick 三个数据字段。
userManager.findUserByID ("userID" = 12345, "status" = true) {
"name",
"age",
"nick"
}
Simple GraphQL 是弱类型的,因此在 GraphQL 查询语句中,选择一个字段之后您不需要为它指名类型,您也不需要为它定义类型。如果我们需要将 nick 字段的名字更名为 userNick。那么可以指定一下别名例如:
userManager.findUserByID ("userID" = 12345, "status" = true) {
"name",
"age",
"userNick" : nick
}
如果用代码的形式,上面这个逻辑看上去会是这个样子的:
UserVO userVO = new UserVO();
UserInfo info = userManager.findUserByID (12345,true);
userVO.setName(info.getName());
userVO.setAge(info.getAge());
userVO.setUserNick(info.getNick());
return userVO;
除此之外,Simple GraphQL 还允许您可以通过查询语句完全的重新组织数据的格式,而不是像前面那样简单的筛选数据字段:
{
"userInfo" : {
"info" : findUserByID ("userID" = 12345) {
"name",
"age",
"nick"
},
"nick" : info.nick
},
"source" : "GraphQL"
}
在这个查询例子中 “"nick" : info.nick” 和上面的遇到的 “"userNick" : nick” 是相同的语法结构,其含义是,查询结果中包含一个 nick 字段,nick 字段的数据来源是。同级属性对象 “info” 中的属性 nick。
例如,如果 userID = 12345 所匹配的 User 对象中 name = “zyc”,age = 30 ,nick = “helo”。那么查询的结果是:
{
"userInfo" : {
"info" : {
"name" : "zyc",
"age" : 30,
"nick" : "helo"
},
"nick" : "helo"
},
"source" : "GraphQL"
}
我们可以看到,userInfo.nick 的值是等于 userInfo.info.nick 的。此外我们还通过 QL 自定义了一个新的字符串属性 source,它的值是 GraphQL。
查询片段
GraphQL 中有片段一说,Simple GraphQL的查询片段目的是为了增强代码可读性。例如下面这个 QL 可以分段写成另外一个:
{
"user" : userManager.findUserByID ("userID" = uid) {
"uid" : userID,
"name",
"age",
"nick"
},
"orderList" : queryOrder ("accountID" = user.uid) [
{
"orderID",
"itemID",
"itemName"
}
]
}
fragment fOrderQL on queryOrder ("accountID" = uid) [
{
"orderID",
"itemID",
"itemName"
}
]
fragment fUserQL on findUserByID ("userID" = uid) {
"userID",
"name",
"age",
"nick"
}
{
"user" : fUserQL,
"orderList" : fOrderQL
}