简介
- GraphQL是一个用于API的查询语言,一个使用基于类型系统来执行查询的服务端运行时
- GraphQL未与任何特定数据库,存储引擎绑定,而是依靠现有代码和数据支撑
查询和变更
字段(Fields)
- GraphQL关于请求对象上的特定字段
- 查询和查询的结果拥有一致的数据结构(很重要)
- 客户端得到想要的数据
- 服务器准确知道客户端请求的字段
- 可以对对象字段进行次级选择
// 查询
{
hero {
name
# 可以添加备注
friends {
name
}
}
}
// 结果
{
"data" : {
"hero": {
"name": "wxy",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
参数(Arguments)
- 每一个字段,嵌套对象都能有自己的一组参数,使得GraphQL可以完美替代多次API获取请求
- 可以给标量(scalar)字段传递参数,GraphQL自带一套默认类型,也可以自己定制类型,来序列化输出格式
Schema和类型
// 查询
{
human(id: "1000") {
name
height
}
}
// 结果
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}
别名(Aliases)
- 通过别名,查询相同字段的不同内容
// 查询不同的hero
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}
// 通过别名,查询不同的hero
{
"data": {
"empireHero": {
"name": "Luke Skywalker"
},
"jediHero": {
"name": "R2-D2"
}
}
}
片段(Fragments)
- GraphQL可复用单元,好的抽象,可以避免重复代码
{
leftComparison: hero(episode: EMPIRE) {
...comparisonFields
}
rightComparison: hero(episode: JEDI) {
...comparisonFields
}
}
fragment comparisonFields on Character {
name
appearsIn
friends {
name
}
}
// 结果
{
"data": {
"leftComparison": {
"name": "Luke Skywalker",
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"friends": [
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
},
{
"name": "C-3PO"
},
{
"name": "R2-D2"
}
]
},
"rightComparison": {
"name": "R2-D2",
"appearsIn": [
"NEWHOPE",
"EMPIRE",
"JEDI"
],
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
操作
一个操作query HeroNameAndFriends
- 操作类型关键字——描述打算做什么类型的操作
- query
- mutation
- subscription
- 操作名称
HeroNameAndFriends
- 想象成函数名,有利于追踪和调试
变量(Variables)
- 查询参数可能是动态的,GraphQL拥有一级方法将动态值提取到查询之外,然后作为分离的字典穿进去。这些动态值,就是变量
- 如何使用变量
- 使用
$variableName
替代查询中的静态值 - 声明
$variableName
为查询接收的变量之一 - 将
variableName: value
通过传输转用(通常是JSON)的分离的变量字典中。
- 使用
- 用法
// 声明
query HeroNameAndFriends($episode: Episode) {
hero(episode: $episode) {
name
friends {
name
}
}
}
// 查询
{
"episode": "JEDI"
}
// 结果
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
变量使用注意事项
- 变量前缀必须为
$
- 声明变量后跟类型,上例中是
Episode
- 所有声明的变量都必须是:
- 标量
- 枚举值
- 输入对象类型(与服务器有关)
- 要传递一个复杂对象到一个字段上,必须知道服务器上匹配的类型。
- 变量定义允许:
- 可选的
- 必要的,在类型后加
!
变量默认值
query HeroNameAndFriends($episode: Episode = "JEDI") {
hero(episode: $episode) {
name
friends {
name
}
}
}
指令(Directives)
- 指令可以附着在字段或者片段包含的字段上,以服务单期待的方式改变查询的执行。
- GraphQL核心规范的两个指令:
-
@include(if: Boolean)
仅在参数为true
,包含被指令附着的字段 -
@skip(if: Boolean)
如果参数为true
,跳过被指令附着的字段
-
变更(Mutations)
- 用来变更服务器数据的方法
- 建议导致写入的操作都应该显式的通过变更(mutation)来发送
- 提价变更同时也可以查询变更后的对象。
// 声明变更
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
// 操作
{
"ep": "JEDI",
"review": {
"stars": 5,
"commentary": "This is a great movie!"
}
}
// 变更后查询结果
{
"data": {
"createReview": {
"stars": 5,
"commentary": "This is a great movie!"
}
}
}
变更中的多个字段
- 查询字段,是并行查询
- 变更字段,是线性执行,保证了变更不会出现 竞争的情况
内联片段(Inline Fragments)
- GraphQL schema 具备自定义接口和联合类型的能力
- 若查询的字段返回的是接口/联合类型,就需要内联片段来去处下层具体类型的数据
//声明
query HeroForEpisode($ep: Episode!) {
hero(episode: $ep) {
name
... on Droid {
primaryFunction
}
... on Human {
height
}
}
}
// 操作
{
"ep": "JEDI"
}
// 结果
{
"data": {
"hero": {
"name": "R2-D2",
"primaryFunction": "Astromech"
}
}
}
元字段(Meta fields)
- GraphQL允许在查询的任何位置请求
__typename
,一个元字段,以获得那个位置的对象
// 声明
{
search(text: "an") {
__typename
... on Human {
name
}
... on Droid {
name
}
... on Starship {
name
}
}
}
// 查询结果
{
"data": {
"search": [
{
"__typename": "Human",
"name": "Han Solo"
},
{
"__typename": "Human",
"name": "Leia Organa"
},
{
"__typename": "Starship",
"name": "TIE Advanced x1"
}
]
}