概念
- GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)
查询和变更
- 字段(Field):GraphQL 是关于请求对象上的特定字段。字段既能指字符串类型,也能指代对象类型。GraphQL查询能够遍历相关对象及其字段,使得客户端可以一次请求查询大量相关数据。
{ hero { name #查询可以有备注! friends { name } } }
{ "data": { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker" }, { "name": "Han Solo" }, { "name": "Leia Organa" } ] } } }
- 参数(Arguments) :可以给字段传递参数。也可以给标量字段传递参数,用于实现服务端的一次转换,而不用每个客户端分别转换。
{ human(id: "1000") { name height(unit: FOOT) } }
{ "data": { "human": { "name": "Luke Skywalker", "height": 5.6430448 } } }
- 别名(Aliases) :设置别名就可以通过不同参数,来查询相同字段。如果不取别名,将会产生冲突。
{ empireHero: hero(episode: EMPIRE) { name } jediHero: hero(episode: JEDI) { name } }
{ "data": { "empireHero": { "name": "Luke Skywalker" }, "jediHero": { "name": "R2-D2" } } }
- 片段(Fragments) :可复用单元,片段使你能够组织一组字段,然后在需要它们的的地方引入。基本语法
fragment xx on xx
{ 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 HeroComparison($first: Int = 3) {leftComparison: hero(episode: EMPIRE) {
…comparisonFields
}
rightComparison: hero(episode: JEDI) {
…comparisonFields
}
}fragment comparisonFields on Character {
name
friendsConnection(first: $first) {
totalCount
edges {
node {
name
}
}
}
}
{
"data": {
"leftComparison": {
"name": "Luke Skywalker",
"friendsConnection": {
"totalCount": 4,
"edges": [
{
"node": {
"name": "Han Solo"
}
},
{
"node": {
"name": "Leia Organa"
}
},
{
"node": {
"name": "C-3PO"
}
}
]
}
},
"rightComparison": {
"name": "R2-D2",
"friendsConnection": {
"totalCount": 3,
"edges": [
{
"node": {
"name": "Luke Skywalker"
}
},
{
"node": {
"name": "Han Solo"
}
},
{
"node": {
"name": "Leia Organa"
}
}
]
}
}
}
}
操作名称(Operation name)
- 操作类型:可以是 query、mutation 或 subscription。描述你打算做什么类型的操作。操作类型是必需的,除非你使用查询简写语法,在这种情况下,你无法为操作提供名称或变量定义。
- 操作名称:是你的操作的有意义和明确的名称。它仅在有多个操作的文档中是必需的,但我们鼓励使用它,因为它对于调试和服务器端日志记录非常有用
query HeroNameAndFriends { hero { name friends { name } } }
变量(Variables):变量定义看上去像是上述查询中的 ($episode: Episode)。其工作方式跟类型语言中函数的参数定义一样。它以列出所有变量,变量前缀必须为 $,后跟其类型,本例中为 Episode。变量都必须是标量、枚举型或者输入对象类型。!代表必填的。可以设置默认变量。
query HeroNameAndFriends($episode: Episode = "JEDI") { hero(episode: $episode) { name friends { name } } }
- 指令(Directives)
- @include(if: Boolean) 仅在参数为 true 时,包含此字段。
- @skip(if: Boolean) 如果参数为 true,跳过此字段。
query Hero($episode: Episode, $withFriends: Boolean!) { hero(episode: $episode) { name friends @include(if: $withFriends) { name } } }
{ "episode": "JEDI", "withFriends": false }
{ "data": { "hero": { "name": "R2-D2" } } }
变更(Mutations:写入的操作都应该显式通过变更(mutation)来发送。
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
查询变更的主要区别:查询字段时,是并行执行,而变更字段时,是线性执行,一个接着一个。内联片段(Inline Fragments)
如果要请求具体类型上的字段,你需要使用一个类型条件内联片段。因为第一个片段标注为 … on Droid,primaryFunction 仅在 hero 返回的 Character 为 Droid 类型时才会执行。同理适用于 Human 类型的 height 字段。
query HeroForEpisode($ep: Episode!) { hero(episode: $ep) { name ... on Droid { primaryFunction } ... on Human { height } } }
__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" } ] } }