概念
- 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"
}
]
}
}