GraphQL是一種的API標準,比REST更加靈活。由Facebook團隊開發,使用他的好處是可以精準獲得想要的數據,不需要經過好幾個請求來獲得你需要的數據。好累,可是還不能睡。

這裡的資料是從GraphQL的官方教學來學習的

使用這個技術的公司有Coursera, Product Hunt, GitHub, Shopify, Pinterest, Twitter(現在叫做X), Meteor, Yelp以及其他公司

下面引用官方的圖

Rest API是大家寫API的時候用的標準。可是現在的需求越來越大,database schema也越來越複雜,為了一個功能可能需要好幾個請求才能達成,但是GraphQL只需要一個請求便可以獲取需要的所有資料

下面來對比REST 和 GraphQL的資料獲取方式

REST vs GraphQL

一個請求便可以獲得所需的資料

當你使用Rest Api,你要實現一個功能可以需要從不同的endpoint獲取資料,可能是/users/<id>來取得用戶的初始資料。然後,也會有像/users/<id>/posts來獲取該用戶的posts。最後在用/users/<id>/followers來獲取用戶的追蹤數

下面引用官方的圖

如果使用GraphQL則只需要向GraphQL服務器發送一個請求,然後服務器會以JSON來返回所需的資料。

下面引用官方的圖

避免不必要的資源浪費

GraphQL不會獲取不需要的資料,或少獲取資料,要多請求造成資源浪費。

Rest Api有個常見的問題就是會從資料庫獲取然後返回超過所需的資料。由於是根據固定的格式返回,要避免浪費也可以細緻地寫,可是會造成很複雜以及代碼量過多。

GraphQL可以對性能有基本的分析

Schema和類型系統的好處

GraphQL用類型系統去定義他的API。所有會暴露在API的類型都會用GraphQL的 Schema Defination Language (SDL)。這個schema會作為client和server的連接來獲取資料。

Schema建立後,前端和後端的員工就不需要頻繁地溝通。

主要概念

Schema Defination Language (SDL)

這裡定義一個簡單的類型Person

type Person {
	name: String!
	age: Int!
}

這個type有亮哥fields,nameage 個別為StringIntStringInt裡的 ! 代表著這個field是資料庫裡的required,也就是必填。

表明表之間的關係

假如說Person與表叫做Post有關聯關係:

type Post {
	title: String!
	author: Person!
}
type Person {
	name: String!
	age: Int!
	posts: [Post!]!
}

所以這裡我們設置一對多的關係,畢竟Posts的fields在Person裡其實是一個array的post

用Query去獲取資料

正常來說如果使用REST API會從某個endpoint獲取某個資料,該endpoint會清楚定義返回的數據。
但是在GraphQL完全是不一樣的,與REST Api返回好幾個endpoint的固定的數據相比,GraphQL只返回一個endpoint,這是因為GraphQL返回的數據是不固定的。
相反地他是由請求者定義需要返回什麼樣的資料

這也意味著請求者需要給服務器更多的資訊來表明他所需的資料。這個資訊就叫query

基本Query寫法

{
	allPersons {
		name
	}
}

這個在這個query裡allPersons 是作為一個query的root field。所有跟著root field的東西,都叫做query的payload。上面的例子中,這個query裡的payload是name。

這個query會返回儲存在資料庫的全部person。下面是一個返回的例子。

{
	"allPersons":[
		{ "name":"Jonny" },
		{ "name":"Sarah" },
		{ "name":"Alice" },
	]
}

這裡你可以注意到雖然person裡面原本有name,age,post
但是這裡只返回了name,這是因為在query裡定義了只返回name

如果請求者也需要age,那就要把age加進query裡面的payload

{
	allPersons {
		name
		age
	}
}

GraphQL還有一個優勢就是,可以原生支持巢狀寫法來獲得數據。
比如說你需要返回一個person裡所有的posts,就跟著這個結構去定義來請求

{
	allPersons {
		name
		age 
		posts {
			title
		}
	}
}

帶參數的Query

GraphQL可以在schema設置0或更多的參數。
舉個栗子,allPersons的field可以有一個last參數來指定返回多少個persons。

{
	allPersons(last: 2) {
		name
	}
}

Query 裡的 Mutations (新增,更新,刪除)

Mutation和query是共用結構的,區別只在只需要在起點添加 mutation的keyword
下面是創建一個新的Person的寫法

mutation {
	createPerson(name: "Bob", age: 36){
		name
		age
	}
}

與之前的例子一樣,Mutation也有一個root field。在這裡叫做createPersoncreatePerson裡的兩個參數對應著新的的personnameage

服務器返回的數據會像這樣

"createPerson":{
	"name":"Bob",
	"age": 36,
}

有一種常見定義schema的方式是當產生一個新的物件的時候會讓服務器產生unique ID。
我們用之前的Person來擴充。

type Person {
	id: ID!
	name: String!
	age: Int!
}

現在當一個新的Person創建後,你可以在mutation的payload裡面直接請求id

mutation {
	createPerson(name: "Alice", age: 36) {
		id
	}
}

用Subscriptions進行實時更新

在現代的需求下,很多app都需要一個與服務器實時連接。這是為了可以馬上獲取重要的event。在這個情境下,GraphQL提供了subscription的概念。

當一個請求者subscribe一個event,他就開始與服務器保持一個穩定的連接,當某個event觸發,服務器就會返回相關的數據。相對的query是需要一個“請求>返回 的循環”,subscription是作為一個“直播”形式發送給請求者。

下面是我們subscribe一個event當Person type發生事件的

subscription {
	newPerson {
		name
		age
	}
}

一旦請求者subscription後,就會與服務器進行穩定的連接。
當有一個Mutation在創建一個新的Person,服務器就會發送關於這個person的數據到請求者

{
	"newPerson": {
		"name": "Jane",
		"age": 23,
	}
}

實作Schema

簡單來說,schema基本上就是一堆GraphQL Types.但是寫給API的時候有幾個root types:

type Query {...}
type Mutation {...}
type Subscription {...}

Query,MutationSubscription 是請求者發送請求的入口點。
如果要開啟allPersons的Query,就要這麼寫。

type Query {
	allPersons: [Person!]!
}

allPersons 是作為一個API的root field。如果我們要設定返回幾個也是使用last參數

type Query {
	allPerson(last: Int): [Person!]!
}

如果是createPerson的Mutation,我們則需要在起點加上Mutation 類型

Mutation type {
	createPerson(name: String!, age: Int!): Person!
}

如果是subscription怎麼需要添加Subscription 類型

type Subsciption {
	newPerson: Person!
}

全部加起來就是一個基本的schema


type Query {
	allPersons(last: Int): [Person!]!
	allPosts(last: Int): [Post!]!
}

type Mutation {
	createPerson(name: String!, age: Int!): Person!
	updatePerson(id: ID!, name: String!, age: Int!):Person!
	deletePerson(id: ID!): Person!
}

type Subscription {
	newPerson: Person!
}

type Person {
	id: ID!
	name: String!
	age: Int!
	posts: [Post!]!
}

type Post {
	title: String!
	author: Person!
}

GraphQL裡的Scalar Type

GraphQL的Type System

Scalar Type

Scalar Type 指的是 GraphQL 的基本型別,總共有五個

  1. Int

  2. Float

  3. String

  4. Boolean

  5. ID

Scalar Type 的用意在於對資料的型態驗證,當你輸入int到一個字串類型就會報錯

这里基本上就是GraphQL的基础,剩下的部分再会!