/

介紹GraphQL

介紹GraphQL

GraphQL是一種用於API的查詢語言,並且還有一組用於執行查詢的伺服器端運行時(在不同的後端語言中實現)。

什麼是GraphQL

GraphQL是API設計中的新領域,以及我們建立和消費API的方式。

它是一種查詢語言,並且還有一組用於執行查詢的伺服器端運行時(在不同的後端語言中實現)。它不依賴於特定的技術,但您可以在任何語言中實現它。

它是一種與REST(REpresentational State Transfer)API直接競爭的方法,就像REST一開始與SOAP競爭一樣。

正如我們將要看到的,它與REST非常不同。它為API設計創造了一個全新的維度。

GraphQL是由Facebook開發的,就像近來撼動JavaScript世界的許多技術一樣,例如React和React Native,於2015年公開推出,盡管在此之前,Facebook在內部使用了幾年。

許多大公司都在採用GraphQL,包括GitHub、Pinterest、Twitter、Sky、紐約時報、Shopify、Yelp和許多其他公司。

當GitHub決定使用該技術實施其API的v4版本時,我首次接觸到GraphQL,並且加入了他們的測試程序。從那時起,我發現它在許多方面都是一個遊戲改變者。

它是如何工作的

GraphQL從您的伺服器暴露單個端點。

您可以使用特殊的查詢語言語法將查詢發送到該端點。該查詢只是一個字符串。

伺服器通過提供一個JSON對象來響應查詢。

讓我們看一個第一個查詢的示例。該查詢獲取id=1的人的名稱:

1
GET /graphql?query={ person(id: "1") { name } }

或:

1
2
3
4
5
{
person(id: "1") {
name
}
}

我們將獲得如下JSON回應:

1
2
3
{
"name": "Tony"
}

讓我們增加一些複雜性:我們從地址(address)對象中提取人的名稱和所在的城市。我們不關心地址的其他詳細信息,所以伺服器不會將它們返回給我們,因為我們並沒有要求它們:

1
GET /graphql?query={ person(id: "1") { name, address { city } } }

1
2
3
4
5
6
7
8
{
person(id: "1") {
name
address {
city
}
}
}

我們得到如下的回應:

1
2
3
4
5
6
{
"name": "Tony",
"address": {
"city": "York"
}
}

正如您所見,我們獲得的數據基本上是我們發送的請求結構,填充了獲取的值。

GraphQL查詢

在本節中,您將了解GraphQL查詢的組成。

我將介紹的概念有:

  • 字段和參數
  • 別名
  • 片段

字段和參數

1
2
3
4
5
{
person(id: "1") {
name
}
}

在此查詢中,您可以看到2個字段,personname,以及1個參數。

字段person返回一個對象,該對象中包含另一個字段,一個字符串。

參數允許我們指定我們想要參考的人。我們傳遞的是一個id,但如果我們所使用的API有按姓名查找人的選項,我們也可以傳遞一個name參數。

參數不限於任何特定的字段。我們可以在person中有一個friends字段,列出該人的朋友,並且它可以有一個limit參數,指定我們希望API返回多少個:

1
2
3
4
5
6
{
person(id: "1") {
name
friends(limit: 100)
}
}

別名

您可以要求API以不同的名稱返回一個字段。例如,在這裡您要求返回name字段,但希望將其作為fullname返回:

1
2
3
4
5
{
owner: person(id: "1") {
fullname: name
}
}

它將返回:

1
2
3
4
5
6
7
{
"data": {
"owner": {
"fullname": "Tony"
}
}
}

這個功能除了為客戶端代碼創建更多的特定命名之外(如果需要的話),還是使查詢在同一查詢中多次引用相同的端點的唯一方法:

1
2
3
4
5
6
7
8
{
owner: person(id: "1") {
fullname: name
}
first\_employee: person(id: "2") {
fullname: name
}
}

片段

在上面的查詢中,我們複製了人的結構。當您具有許多類似字段時,片段允許我們只指定結構一次(這在有許多相似字段時非常有用):

1
2
3
4
5
6
7
8
9
10
11
12
{
owner: person(id: "1") {
...personFields
}
first\_employee: person(id: "2") {
...personFields
}
}

fragment personFields on person {
fullname: name
}

GraphQL變量

更複雜的GraphQL查詢需要使用變量,一種動態指定查詢中使用的值的方法。

在這種情況下,我們將人的id作為字符串添加到查詢中:

1
2
3
4
5
{
owner: person(id: "1") {
fullname: name
}
}

id在我們的程序中可能會動態更改,因此我們需要一種通過參數傳遞它的方式,而不是使用字符串插值。

使用變量,可以將相同的查詢寫成如下形式:

1
2
3
4
5
6
7
8
9
query GetOwner($id: String) {
owner: person(id: $id) {
fullname: name
}
}

{
"id": "1"
}

在此片段中,我們使用GetOwner這個名稱指定了我們的查詢。可以將其視為具名函數,而先前則是匿名函數。在應用程序中有許多查詢時,具有命名的查詢很有用。

帶有變量的查詢定義看起來像函數定義,並且它以相同的方式工作。

讓變量成為必填項目

!添加到類型後:

1
query GetOwner($id: String!)

而不是$id: String將使變量$id變成必填項目。

為變量指定默認值

可以使用以下語法指定默認值:

1
query GetOwner($id: String = "1")

GraphQL指令

指令允許您根據變量的真假情況包含或排除字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
query GetPerson($id: String) {
person(id: $id) {
fullname: name,
address: @include(if: $getAddress) {
city
street
country
}
}
}

{
"id": "1",
"getAddress": false
}

在這種情況下,如果我們傳遞的getAddress變量為true,我們還會得到address字段,否則不會。

我們有2個可用的指令:include,我們剛剛見過(如果為true則包括),以及skip,它是其相反的操作(如果為true則跳過)。

include(如果:布爾值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
query GetPerson($id: String) {
person(id: $id) {
fullname: name,
address: @include(if: $getAddress) {
city
street
country
}
}
}

{
"id": "1",
"getAddress": false
}

skip(如果:布爾值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
query GetPerson($id: String) {
person(id: $id) {
fullname: name,
address: @skip(if: $excludeAddress) {
city
street
country
}
}
}

{
"id": "1",
"excludeAddress": false
}