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
的人的名稱:
GET /graphql?query={ person(id: "1") { name } }
或:
{
person(id: "1") {
name
}
}
我們將獲得如下JSON回應:
{
"name": "Tony"
}
讓我們增加一些複雜性:我們從地址(address
)對象中提取人的名稱和所在的城市。我們不關心地址的其他詳細信息,所以伺服器不會將它們返回給我們,因為我們並沒有要求它們:
GET /graphql?query={ person(id: "1") { name, address { city } } }
或
{
person(id: "1") {
name
address {
city
}
}
}
我們得到如下的回應:
{
"name": "Tony",
"address": {
"city": "York"
}
}
正如您所見,我們獲得的數據基本上是我們發送的請求結構,填充了獲取的值。
GraphQL查詢
在本節中,您將了解GraphQL查詢的組成。
我將介紹的概念有:
- 字段和參數
- 別名
- 片段
字段和參數
{
person(id: "1") {
name
}
}
在此查詢中,您可以看到2個字段,person
和name
,以及1個參數。
字段person
返回一個對象,該對象中包含另一個字段,一個字符串。
參數允許我們指定我們想要參考的人。我們傳遞的是一個id
,但如果我們所使用的API有按姓名查找人的選項,我們也可以傳遞一個name
參數。
參數不限於任何特定的字段。我們可以在person
中有一個friends
字段,列出該人的朋友,並且它可以有一個limit
參數,指定我們希望API返回多少個:
{
person(id: "1") {
name
friends(limit: 100)
}
}
別名
您可以要求API以不同的名稱返回一個字段。例如,在這裡您要求返回name
字段,但希望將其作為fullname
返回:
{
owner: person(id: "1") {
fullname: name
}
}
它將返回:
{
"data": {
"owner": {
"fullname": "Tony"
}
}
}
這個功能除了為客戶端代碼創建更多的特定命名之外(如果需要的話),還是使查詢在同一查詢中多次引用相同的端點的唯一方法:
{
owner: person(id: "1") {
fullname: name
}
first\_employee: person(id: "2") {
fullname: name
}
}
片段
在上面的查詢中,我們複製了人的結構。當您具有許多類似字段時,片段允許我們只指定結構一次(這在有許多相似字段時非常有用):
{
owner: person(id: "1") {
...personFields
}
first\_employee: person(id: "2") {
...personFields
}
}
fragment personFields on person {
fullname: name
}
GraphQL變量
更複雜的GraphQL查詢需要使用變量,一種動態指定查詢中使用的值的方法。
在這種情況下,我們將人的id
作為字符串添加到查詢中:
{
owner: person(id: "1") {
fullname: name
}
}
id
在我們的程序中可能會動態更改,因此我們需要一種通過參數傳遞它的方式,而不是使用字符串插值。
使用變量,可以將相同的查詢寫成如下形式:
query GetOwner($id: String) {
owner: person(id: $id) {
fullname: name
}
}
{
"id": "1"
}
在此片段中,我們使用GetOwner
這個名稱指定了我們的查詢。可以將其視為具名函數,而先前則是匿名函數。在應用程序中有許多查詢時,具有命名的查詢很有用。
帶有變量的查詢定義看起來像函數定義,並且它以相同的方式工作。
讓變量成為必填項目
將!
添加到類型後:
query GetOwner($id: String!)
而不是$id: String
將使變量$id變成必填項目。
為變量指定默認值
可以使用以下語法指定默認值:
query GetOwner($id: String = "1")
GraphQL指令
指令允許您根據變量的真假情況包含或排除字段。
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(如果:布爾值)
query GetPerson($id: String) {
person(id: $id) {
fullname: name,
address: @include(if: $getAddress) {
city
street
country
}
}
}
{
"id": "1",
"getAddress": false
}
skip(如果:布爾值)
query GetPerson($id: String) {
person(id: $id) {
fullname: name,
address: @skip(if: $excludeAddress) {
city
street
country
}
}
}
{
"id": "1",
"excludeAddress": false
}