GraphQL

是什么?

​ 面向数据的API查询风格。传统的 API 拿到的是前后端约定好的数据格式,GraphQL 对 API 中的数据提供了一套易于理解的完整描述,客户端能够准确地获得它需要的数据,没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

重要概念

操作类型

  • Query(查询):获取数据
  • Mutation(变更):对数据进行变更,比如增加、删除、修改
  • Subscription(订阅):当数据发生变更时,进行消息推送

​ 在Query查询字段时,是并行执行的;而在Mutation变更时,是线性执行的,一个接着一个。

对象类型[object type]和标量类型[scalar type]

  • 对象类型:用户在schema中定义的type
  • 标量类型:内置的标量类型例如String Int Float Boolean ID等,用户也可以自定义标量类型

​ 若GraphQL服务接收了一个query,那么这个query将从Root Query开始查找,找到对象类型[object type]时则使用它的解析函数Resolver来获取内容,如果返回的是对象类型则继续使用解析函数获取内容,如果获取返回的是标量类型则结束获取,直到找到最后一个标量类型。

schema[模式]

​ schema定义了字段的类型、数据的结构,描述了接口数据请求的规则。schema使用简单的强类型模式语法,称为模式描述语言(schema definition language, SDL)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type Query{
hello: String
users: [User]!
user(id: String): [User]!
}
type Mutation{
createUser(id: ID!, name: String!, email: String!, age: Int, gender: Gender): User!
updateUser(id: ID!, name: String!, email: String!, age: Int, gender: Gender): User!
deleteUser(id: ID!): User
}
type Subscription{
subsUser(id: ID!): User
}
type User implements UserInterface{
id: ID!
name: String!
age: Int
gender: Gender
email: String
}
enum Gender{
MAN
WOMAN
}
interface UserInterface{
id: ID!
name: String!
age: Int
gender: Gender
}

解析函数Resolver

​ 前端请求到达后端后,需要由解析函数Resolver来提供数据。例如有一个Query:

1
2
3
query{
hello
}

​ 同名解析函数则为:

1
2
3
4
5
Query: {
hello(parent, args, context, info){
return...
}
}

​ 解析函数接收四个参数,分别为:

  • parent:当前上一个解析函数的返回值
  • args:查询中传入的参数
  • context:提供给所有解析器的上下文信息
  • info:一个保存与当前查询相关的字段特定信息以及schema详细信息的值

​ 解析函数的返回值可以是一个具体的值,也可以是Promise或Promise数组。

请求格式

​ GraphQL最常见的是通过HTTP来发送请求。

​ 例如,通过GET/POST方式来执行下面的GraphQL查询:

1
2
3
4
5
query{
me{
name
}
}

​ GET是将请求内容放在URL中,POST是在content-type: application/json情况下,将JSON格式的内容放在请求体中。

1
2
3
4
5
6
7
8
9
// GET
http: //example/graphql?query={me{name}}

// POST
{
"query": "...",
"operationName": "...",
"variables": {"myVariable": "someValue", ...}
}

​ 返回的格式一般为JSON格式:

1
2
3
4
5
6
7
8
9
// 正确返回
{
"data": {...}
}

// 错误返回
{
"errors": [...]
}