GraphQL 第一章 查询和变更
What ? When ? Where ? Why ? How ?
GraphQL 是什么?
GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时。
GraphQL 包括两部分:定义的类型和类型上的字段(Schema),每个类型上的每个字段的解析函数(Resolvers)
为什么要用 GraphQL ?
1. GraphQL 是强类型的 Schema 。是每个 GraphQL API 的基础,它清晰的定义了每个 API 支持的操作,包括输入的参数和返回的内容
2. 按需获取。从 API 获取想要的数据,不必依赖 REST 端口返会的固定数据结构。获取的结果是可预测的。解决了 Overfetching 和 Underfetching
- Overfetching 意味着前端得到了实际不需要的数据,造成了性能和带宽的浪费
- Underfetching 获取的数据中缺少,需要通过额外的请求去获取需要的数据。
3. GraphQL 支持快速产品开发。前端开发可以使用诸多库(APollo、Relay 或Urql),可以用缓存、实时更新UI等功能
4. GraphQL 可以组合使用。Schema 拼接是 GraphQL 的新概念之一。可以组合和链接多个 GraphQL API 合并为一个(一个 GraphQL API 可以由多个 GraphQL API 构成),避免了与多个 GraphQL 端点的通信,只需处理单个 API 端点,而协调与各种服务通信的复杂性从前端隐藏了。
5. 完善的社区资源。比如graphql-tools 等,可以在 nodejs 环境中运行,同时可以与 express 和 koa 结合使用。
什么时候用 GraphQL ?哪里用 GraphQL ?
用不用取决于你自己,在哪里用也看你自己了
GraphQL API 的目的
创建API的目的是使自己的软件具有可以被其他外部服务集成的能力。即使你的程序被单个前端程序所使用,也可以将此前端视为外部服务,为此,当通过API为两者之间提供通信时,你能够在不同的项目中工作。
如果你在一个大型团队中工作,可以将其拆分为创建前端和后端团队,从而允许他们使用相同的技术,并使他们的工作更轻松。
怎么去用 GraphQL ?
GraphQL 查询能够遍历相关对象及其字段,使得客户端可以一次请求查询大量相关数据,而不像传统 REST 架构中那样需要多次往返查询。
{
hero {
name
# 查询的备注
frinds {
name
}
}
}
# 最后的结果结构
{
data: {
hero:{
name:"xxxx",
friends:[
{name:'yyy'},
{name:'zzzz'}
]
}
}
}
在查询的过程中,我们还会根据我们传递的参数来进行查询
每一个字段和嵌套对象都能有自己的一组参数,从而使得 GraphQL 可以完美替代多次 API 获取请求。甚至你也可以给 标量(scalar)字段传递参数,用于实现服务端的一次转换,而不用每个客户端分别转换。
# 基本的传参
{
hero(id: 1){
name
}
}
# 转换传递过来的数据
{
hero(id: 1){
name
height(unit: FOOT) # 结果:5.2245 这样的浮点数 FOOT 是一个枚举类型,之后会讲到
}
}
我们会遇到这样一种情况,就是无法通过不同参数来查询相同的字段,因此这里我们就用到了别名(Aliases)
# 这样的情况下我们就无法区分结果了
{
hero(id: 1) { id, name, nickname, age }
hero(id :2) { id, name, nickname, age }
}
# 因此我们这里就可以用到别名
{
hero1: hero(id: 1) { id, name, nickname, age }
hero2: hero(id :2) { id, name, nickname, age }
}
# -----> 结果就通过别名进行区分了
{
data: {
hero1:{ name: 'xxxx', ...},
hero2:{ name: 'zzzz', ...}
}
}
我们发现,上看我们在获取数据的时候,重复写了 id, name, nickname, age
这些字段,这其实还好,字段不算多,如果我们定义的一个对象是很复杂的,并且字段繁多的,我们虽然通过 CV 大法可以简单的就复制过来,但是这样的操作很 low,因此我们可以想到一种方式,你就是把重复的字段进行一个抽离封装。graphql 中就提供了相应的处理方式片段(Fragments)
注:片段不能引用其自身或者创建回环,因为会导致结果无边界
{
hero1: hero(id: 1) { ...person }
hero2: hero(id :2) { ...person }
}
fragment person on Charactor {
id
name
nickname
age
}
# 在片段内也是可以使用变量的
fragment person on Charactor {
id
name
nickname
age
getFriend(id: $id){ # 变量马上就要讲了
name
}
}
上面我们也写了好些个 graphql 的查询,但是上面这些都是简写的形式,我们省略了操作类型以及查询的名称
操作类型:有三种分别是query 、 mutation 、subscription
查询名称:这个是自己定义的,为了让你的操作更加语义话,方便阅读
之前我们在获取某些特定数据的时候会传递参数,但是我们传递的参数是写死的,但是实际中我们肯定会动态的传递某些参数,因此就需要用变量的方式来动态接受相应的数据。
修改我们上面通过 id 获取相应 hero