看完復聯四,我整理了這份 GraphQL 入門教程,哈哈真香。。。
首先有請阿爸鎮貼!哈哈哈,需要高清原圖的小夥伴可以 點我下載 阿爸無敵 。
下面開始本文內容:
一、GraphQL介紹
GraphQL
是 Facebook 開發的一種 API 的查詢語言,與 2015 年公開發布,是 REST API 的替代品。
GraphQL
既是一種用於 API 的查詢語言也是一個滿足你資料查詢的執行時。 GraphQL
對你的 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。
官網: graphql.org/
中文網: graphql.cn/
1. 特點
- 請求你所要的資料,不多不少;
如:hero
中有 name
, age
, sex
等,可以只取得需要的欄位。
- 獲取多個資源,只用一個請求;
典型的 REST API
請求多個資源時得載入多個 URL,而 GraphQL
可以通過一次請求就獲取你應用所需的所有資料。這樣也能保證在較慢的行動網路連線下,使用 GraphQL
的應用也能表現得足夠迅速。
- 描述所有可能型別的系統。便於維護,根據需求平滑演進,新增或隱藏欄位;
GraphQL
使用型別來保證應用只請求可能的資料,還提供了清晰的輔助性錯誤資訊。應用可以使用型別,而避免編寫手動解析程式碼。
2. 簡單案例
這裡先看下簡單案例,體驗下 GraphQL
的神奇之處(後面詳細介紹)。
我們這樣定義查詢語句:
query {
hero
}
複製程式碼
然後得到的就是我們所要查詢的 hero
欄位:
{
"data": {
"hero": "I'm iron man"
}
}
複製程式碼
這樣用起來,是不是更舒服呢?
二、GraphQL與restful對比
1. restful介紹
全稱:Representational State Transfer
表屬性狀態轉移。
本質上就是定義 uri ,通過 API 介面來取得資源。通用系統架構,不受語言限制。
例子: 餓了嗎介面。
如:介面 restapi/shopping/v3/restaurants?latitude=13
就是個典型的 restful
介面,定義資源 + 查詢條件。
2. 與 GraphQL 比較
-
restful
一個介面只能返回一個資源,GraphQL
一次可以獲取多個資源。 -
restful
用不同 url 來區分資源,GraphQL
用型別區分資源。
三、使用express構建基本helloworld
1. 簡單案例
首先建立一個資料夾 demo
,並初始化一個 package.json
,安裝 express
/ graphql
/ express-graphql
依賴包:
npm init -y
npm install express graphql express-graphql -S
複製程式碼
新建一個 hello.js
,引入檔案:
const express = require('express')
const { buildSchema } = require('graphql')
const graphqlHTTP = require('express-graphql')
複製程式碼
建立一個 schema
來定義查詢語句和型別,buildSchema()
方法需要傳入的引數是字串型別,如下面的 hero
查詢欄位,後面的 String
型別表示欄位返回的資料型別:
const schema = buildSchema(`
type Query {
hero: String
}
`)
複製程式碼
建立一個 root
處理器,處理對應的查詢,這裡的 hello
處理器對應的是 schema
中的 hero
欄位查詢的處理,這裡直接返回 I'm iron man
的結果:
const root = {
hero: () => {
return "I'm iron man"
}
}
複製程式碼
當然,處理器中也可以是其他複雜操作,後面會介紹。
然後例項化 express
,並且將路由轉發給 graphqlHTTP
處理:
const app = express()
app.use('/graphql', graphqlHTTP({
schema,
rootValue: root,
graphiql: true
}))
app.listen(3000)
複製程式碼
graphqlHTTP
中的三個引數介紹:
schema
:定義的查詢語句和型別rootValue
:處理對應查詢的處理器graphiql
:是否開啟除錯視窗,開發階段開啟,生產階段關閉
接下來執行專案,在命令列中執行 node hello.js
,這裡可以在 graphiql
上做除錯,開啟地址 localhost:3000/graphiql
就可以愉快的查詢了。
另外我們可以在 graphiql
介面右側開啟 Docs 檢視我們定義的所有欄位和描述資訊。
最終程式碼:
const express = require('express')
const { buildSchema } = require('graphql')
const graphqlHTTP = require('express-graphql')
// 構建schema,這裡定義查詢的語句和型別
const schema = buildSchema(`
type Query {
hero: String
}
`)
// 定義查詢所對應的 resolver,也就是查詢對應的處理器
const root = {
hero: () => {
return "I'm iron man"
}
}
const app = express()
// 將路由轉發給 graphqlHTTP 處理
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}))
app.listen(3000)
複製程式碼
2. 自定義型別查詢
我們前面的查詢中,已經將 hero
欄位定義為 String
型別,但是常常開發中,我們又會碰到欄位是多個型別,即欄位也能指代物件型別(Object),比如一個 user
欄位會有 name
、age
等欄位,而 name
返回字串型別,age
返回數值型別。
這時候,我們可以對這個物件的欄位進行次級選擇(sub-selection)。GraphQL 查詢能夠遍歷相關物件及其欄位,使得客戶端可以一次請求查詢大量相關資料,而不像傳統 REST 架構中那樣需要多次往返查詢。
我們可以新建一個查詢型別來定義 user
欄位返回的型別:
const schema = buildSchema(`
type User {
# 查詢可以有備註!
name: String
age: Int
}
type Query {
hero: String
user: User
}
`)
複製程式碼
在處理器中我們也要加上:
const root = {
hero: () => {
return "I'm iron man"
},
user: () => {
return {
name: 'leo',
age: 18
}
}
}
複製程式碼
這邊 Int/String 引數型別的問題,下一章介紹
四、引數型別和引數傳遞
1. 基本引數型別
String
, Int
, Float
, Boolean
和 ID
,這些基本引數型別可以在 schema
宣告中直接使用。
Int
:有符號 32 位整數。Float
:有符號雙精度浮點值。String
:UTF‐8
字元序列。Boolean
:true
或者false
。ID
:ID
標量型別表示一個唯一識別符號,通常用以重新獲取物件或者作為快取中的鍵。ID
型別使用和String
一樣的方式序列化;然而將其定義為ID
意味著並不需要人類可讀型。
另外,我們可以使用 [型別]
來表示一類陣列,如:
[Int]
表示整型陣列;[String]
表示字串型陣列;
2. 引數傳遞
使用方式和 JS 引數傳遞一樣,小括號內定義形參,但是引數需要定義型別。
使用 !
代表引數不能為空。
下面案例:引數 teamName
是 String
型別,必須傳遞,而 number
引數也是 Int
型別,但是是非必須傳遞,最後輸出的結果也是 String
型別。
type Query {
getHero(teamName: String!, number: Int): [String]
}
複製程式碼
下面一個案例:
//...省略其他
const schema = buildSchema(`
type Query {
getHero(teamName: String!): [String]
}
`)
const root = {
getHero: ({teamName}) => {
// 這裡的操作 實際開發中常常用在請求資料庫
const hero = {
'三國': ['張飛', '劉備', '關羽'],
'復仇者聯盟': ['鋼鐵俠', '美國隊長', '綠巨人']
}
return hero[teamName]
}
}
//...省略其他
複製程式碼
這時候我們在 GraphiQL 上輸入查詢,就會得到 復仇者聯盟 的英雄資料了。
// 查詢
query {
getHero(teamName:"復仇者聯盟")
}
// 結果
{
"data": {
"getHero": [
"鋼鐵俠",
"美國隊長",
"綠巨人"
]
}
}
複製程式碼
3. 自定義返回型別
在實際開發中,我們返回的資料型別可能是一個物件,物件中可能既有 Int
型別的屬性,也有 String
型別的值,等等,這裡我們可以使用 自定義返回型別 來處理:
//...省略其他
const schema = buildSchema(`
type Hero {
name: String
age: Int
doSomething(thing: String): String
}
type Query {
getSuperHero(heroName: String!): Hero
}
`)
const root = {
getSuperHero: ({heroName}) => {
// 這裡的操作 實際開發中常常用在請求資料庫
const name = heroName
const age = 18
const doSomething = ({thing}) => {
return `I'm ${name}, I'm ${thing} now`
}
return { name, age, doSomething }
}
}
//...省略其他
複製程式碼
這裡指定了 getSuperHero
欄位的返回型別是 Hero
型別,隨後在上面定義了 Hero
。
其中 Hero
型別中的 doSomething
也是可以傳遞指定型別引數,並且指定返回型別。
下面看下輸出情況:
// 查詢
query {
getSuperHero(heroName:"IronMan") {
name
age
doSomething
}
}
// 結果
{
"data": {
"getSuperHero": {
"name": "IronMan",
"age": 46,
"doSomething": "I'm IronMan, I'm undefined now"
}
}
}
複製程式碼
這裡也可以給 doSomething
傳遞引數,就會獲取到不同結果:
// 查詢
query {
getSuperHero(heroName:"IronMan") {
name
age
doSomething(thing:"watching TV")
}
}
// 結果
{
"data": {
"getSuperHero": {
"name": "IronMan",
"age": 46,
"doSomething": "I'm IronMan, I'm watching TV now"
}
}
}
複製程式碼
五、GraphQL客戶端
這一節我們學習如何在客戶端中訪問 graphql
的介面。
1. 後端定義介面
我們先在後端將介面開發完成,這裡跟前面差不多,但需要多一步,使用 express
向外暴露一個資料夾,供使用者訪問靜態資原始檔:
這裡直接使用前一節的程式碼啦~
// index.js 開發 graphql 介面
//...省略其他
const schema = buildSchema(`
type Hero {
name: String
age: Int
doSomething(thing: String): String
}
type Query {
getSuperHero(heroName: String!): Hero
}
`)
const root = {
getSuperHero: ({heroName}) => {
// 這裡的操作 實際開發中常常用在請求資料庫
const name = heroName
const age = 46
const doSomething = ({thing}) => {
return `I'm ${name}, I'm ${thing} now`
}
return { name, age, doSomething }
}
}
const app = express()
app.use('/graphql', graphqlHTTP({
schema, rootValue: root, graphiql: true
}))
// 公開資料夾 使使用者訪問靜態資源
app.use(express.static('public'))
app.listen(3000)
複製程式碼
這樣我們就給前端頁面提供一個可以訪問靜態資源的功能。
這裡還需要在根目錄建立一個 public 資料夾,並在資料夾中新增 index.html
檔案,此時的目錄結構:
|-node_modules
|-public
|---index.html
|-index.js
|-package.json
複製程式碼
2. 前端頁面請求
然後給 index.html
新增按鈕和事件繫結:
這裡的變數 query
是個字串型別,定義查詢條件,在條件 GetSuperHero
中的引數,需要用 $
符號來標識,並在實際查詢 getSuperHero
中,作為引數的引數型別設定進來。
然後定義變數 variables
,指定屬性的值,之後通過 fetch
發起請求:
<button onclick="getData()">獲取資料</button>
<script>
function getData(){
const query = `
query GetSuperHero($heroName: String, $thing: String){
getSuperHero(heroName: $heroName){
name
age
doSomething(thing: $thing)
}
}
`
// 如果不需要其他引數 至少要傳一個引數 否則會報錯
// const query = `
// query GetSuperHero($heroName: String){
// getSuperHero(heroName: $heroName){
// name
// }
// }
// `
const variables = {heroName: '鋼鐵俠', thing: 'watching TV'}
fetch('./graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
query, variables
})
})
.then(res => res.json())
.then(json => {
console.log(json)
})
}
</script>
複製程式碼
當我們寫完以後,點選 獲取資料 就會在控制檯列印下面的資料:
{
"data":{
"getSuperHero":{
"name":"鋼鐵俠",
"age":46,
"doSomething": "I'm 鋼鐵俠, I'm watching TV now"
}
}
}
複製程式碼
3. 注意點
- 請求中的
query
引數需要對照好有$
符號的變數。
查詢語句 query GetSuperHero($heroName: String)
裡引數 $heroName
中的 heroName
;
查詢語句 getSuperHero(heroName: $heroName)
裡型別 $heroName
中的 heroName
;
變數 variables
中的 heroName
屬性;
這三個名稱需要一樣。
- 請求中需要將資料序列化操作。
body: JSON.stringify({ query, variables })
複製程式碼
六、使用Mutations修改資料
1. Mutation 使用
根據前面的學習,我們知道,要做查詢操作,需要使用 Query
來宣告:
type Query {
queryHero(heroName: String): String
}
複製程式碼
當我們要做修改操作,需要用到的是 Mutation
:
type Mutation {
createHero(heroName: String): String
}
複製程式碼
如果 Mutation
中欄位的形參是自定義型別,則型別需要用 input
標識:
const schema = buildSchema(`
# 輸入型別 用 input 標識
input HeroInput {
name: String
age: Int
}
# 查詢型別
type Hero {
name: String
age: Int
}
type Mutation {
createHero(heroName: String): Hero
updateHero(heroName: String, hero: HeroInput): Hero
}
`)
複製程式碼
注意下:這裡需要至少定義一個 Query
不然GraphiQL
會不顯示查詢:
type Query {
hero: [Hero]
}
複製程式碼
2. Mutation 使用案例
先建立一個 schema
,內容為上一步【1. Mutation 使用】中定義的內容,這裡不重複寫。
然後模擬建立一個本地資料庫 localDb
, 用於模擬存放新增的超級英雄資料:
const localDb = {}
複製程式碼
接下來宣告 root
實現 schema
中的欄位方法:
const root = {
hero() {
// 這裡需要轉成陣列 因為前面定義了返回值是 [Hero] 型別
let arr = []
for(const key in localDb){
arr.push(localDb[key])
}
return arr
},
createHero({ input }) {
// 相當於資料庫的新增操作
localDb[input.name] = input
return localDb[input.name]
},
updateHero({ id, input }) {
// 相當於資料庫的更新操作
const update = Object.assign({}, localDb[id], input)
localDb[id] = update
return update
}
}
複製程式碼
最後配置 graphqlHTTP
方法和啟動伺服器,這裡就不多重複咯。
最終程式碼:
//...省略其他
const schema = buildSchema(`
# 輸入型別 用 input 標識
input HeroInput {
name: String
age: Int
}
# 查詢型別
type Hero {
name: String
age: Int
}
type Mutation {
createHero(input: HeroInput): Hero
updateHero(id: ID!, input: HeroInput): Hero
}
# 需要至少定義一個 Query 不要GraphiQL會不顯示查詢
type Query {
hero: [Hero]
}
`)
const localDb = {}
const root = {
hero() {
// 這裡需要轉成陣列 因為前面定義了返回值是 [Hero] 型別
let arr = []
for(const key in localDb){
arr.push(localDb[key])
}
return arr
},
createHero({ input }) {
// 相當於資料庫的新增操作
localDb[input.name] = input
return localDb[input.name]
},
updateHero({ id, input }) {
// 相當於資料庫的更新操作
const update = Object.assign({}, localDb[id], input)
localDb[id] = update
return update
}
}
//...省略其他
複製程式碼
現在我們可以啟動伺服器,在 GraphiQL
上測試下效果了。
我們是使用 mutation
的 createHero
欄位新增兩條資料:
mutation {
createHero(input: {
name: "鋼鐵俠"
age: 40
}){
name
age
}
}
複製程式碼
mutation {
createHero(input: {
name: "美國隊長"
age: 41
}){
name
age
}
}
複製程式碼
然後使用 query
的 hero
欄位查詢新增的結果:
query {
hero {
name
age
}
}
複製程式碼
這樣我們就獲取到剛才的新增結果:
{
"data": {
"hero": [
{
"name": "鋼鐵俠",
"age": 40
},
{
"name": "美國隊長",
"age": 41
}
]
}
}
複製程式碼
然後我們開始更新資料,使用 mutation
的 updateHero
欄位將 美國隊長 的 age
值修改為 18:
mutation {
updateHero(id: "美國隊長", input: {
age: 18
}){
age
}
}
複製程式碼
再使用 query
的 hero
欄位查詢下新的資料,會發現 美國隊長 的 age
值已經更新為 18:
{
"data": {
"hero": [
{
"name": "鋼鐵俠",
"age": 40
},
{
"name": "美國隊長",
"age": 18
}
]
}
}
複製程式碼
七、認證和中介軟體
我們知道,修改資料的介面不能讓所有人隨意訪問,所以需要新增許可權認證,讓有許可權的人才可以訪問。
在 express
中,可以很簡單的使用中介軟體來將請求進行攔截,將沒有許可權的請求過濾並返回錯誤提示。
中介軟體實際上是一個函式,在介面執行之前,先攔截請求,再決定我們是否接著往下走,還是返回錯誤提示。
這在【六、使用Mutations修改資料】的最終程式碼上,在新增這個中介軟體:
//... 省略其他
const app = express()
const middleWare = (req, res, next) => {
// 這裡是簡單模擬許可權
// 實際開發中 更多的是和後端進行 token 交換來判斷許可權
if(req.url.indexOf('/graphql') !== -1 && req.headers.cookie.indexOf('auth') === -1){
// 向客戶端返回一個錯誤資訊
res.send(JSON.stringify({
err: '暫無許可權'
}))
return
}
next() // 正常下一步
}
// 註冊中介軟體
app.use(middleWare)
//... 省略其他
複製程式碼
這裡的許可權判斷,只是簡單模擬,實際開發中,更多的是和後端進行 token
交換來判斷許可權(或者其他形式)。
我們重啟伺服器,開啟 http://localhost:3000/graphql
,發現頁面提示錯誤了,因為 cookies
中沒有含有 auth
字串。
如果這裡提示 TypeError: Cannot read property 'indexOf' of undefined
,可以先不用管,因為瀏覽器中沒有 cookies
的原因,其實前面的許可權判斷邏輯需要根據具體業務場景判斷。
為了方便測試,我們在 chrome 瀏覽器控制檯的 application
下,手動設定一個含有 auth
字串的一個 cookies
,只是測試使用哦。
設定完成後,我們就能正常進入頁面。
八、ConstructingTypes
在前面的介紹中,我們要建立一個 schema
都是使用 buildSchema
方法來定義,但我們也可以使用另外一種定義方式。
就是這裡要學習使用的建構函式 graphql.GraphQLObjectType
定義,它有這麼幾個優點和缺點:
- 優點:報錯提醒更直觀,結構更清晰,更便於維護。
- 缺點:程式碼量上升。
1. 定義type(型別)
這裡先將前面定義的 Hero
型別進行改造:
const graphql = require('graphql') // 需要引入
const HeroType = new graphql.GraphQLObjectType({
name: 'Hero',
fields: {
name:{ type: graphql.GraphQLString },
age:{ type: graphql.GraphQLInt },
}
})
複製程式碼
兩者區別在於:
區別 | buildSchema |
graphql.GraphQLObjectType |
---|---|---|
引數型別 | 字串 | 物件 |
類名 | 跟在 type 字元後面,這裡是 type Hero |
在引數物件的 name 屬性上 |
屬性定義 | 定義在型別後,鍵值對形式 | 定義在引數物件 fields 屬性中,值為物件,每個屬性名為鍵名,值也是物件,其中 type 屬性的值為 graphql 中的屬性,下面會補充 |
補充:
fields
屬性中的子屬性的型別通常有:
graphql.GraphQLString
graphql.GraphQLInt
graphql.GraphQLBoolean
....
即在 GraphQL
後面跟上基本型別名稱。
2. 定義query(查詢)
定義查詢的時候,跟之前類似,可以參照下面對比圖理解,這裡比較不同的是,多了個 resolve
的方法,這個方法是用來執行處理查詢的邏輯,其實就是之前的 root
中的方法。
const QueryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: {
// 一個個查詢方法
getSuperHero: {
type: HeroType,
args: {
heroName: { type: graphql.GraphQLString }
},
// 方法實現 查詢的處理函式
resolve: function(_, { heroName }){
const name = heroName
const age = 18
return { name, age }
}
}
}
})
複製程式碼
3. 建立 schema
建立的時候只需例項化並且將引數傳入即可:
// step3 構造 schema
const schema = new graphql.GraphQLSchema({ query: QueryType})
複製程式碼
最後使用也是和前面一樣:
const app = express()
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}))
app.listen(3000)
複製程式碼
九、與資料庫結合實戰
我們試著使用前面所學的內容,開發一個簡單的實踐專案:
通過 GraphiQL
頁面,往 Mongodb
中插入和更新資料,主要用到【六、使用Mutations修改資料】章節的操作。
1. 搭建並啟動本地 Mongodb 資料庫
首先我們可以到 Mongodb 官網 選擇對應平臺和版本下載安裝。
下載安裝步驟,可以參考 mongoDB下載、安裝和配置,這裡就不多介紹喲~~
安裝完成後,我們開啟兩個終端,分別執行下面兩行命令:
// 終端1 啟動資料庫
mongod --dbpath c:\leo\app\mongodb\data\db
// 終端2 進入資料庫命令列操作模式
mongo
複製程式碼
2. 連線資料庫,建立 Schema 和 Model
首先我們新建一個檔案 db.js
,並 npm install mongoose
安裝 mongoose
,然後寫入下面程式碼,實現連線資料庫:
const express = require('express')
const { buildSchema } = require('graphql')
const graphqlHTTP = require('express-graphql')
const mongoose = require('mongoose')
const DB_PATH = 'mongodb://127.0.0.1:27017/hero_table'
const connect = () => {
// 連線資料庫
mongoose.connect(DB_PATH)
// 連線斷開
mongoose.connection.on('disconnected', () => {
mongoose.connect(DB_PATH)
})
// 連線失敗
mongoose.connection.on('error', err => {
console.error(err)
})
// 連線成功
mongoose.connection.on('connected', async () => {
console.log('Connected to MongoDB connected', DB_PATH)
})
}
connect()
複製程式碼
然後建立 Schema
和 Model
:
let HeroSchema = new mongoose.Schema({
name: String,
age: Number
})
let HeroModel = mongoose.model('hero',HeroSchema, 'hero_table')
複製程式碼
3. 宣告查詢語句
這一步,還是先使用【六、使用Mutations修改資料】章節的操作邏輯,也就是先用字串建立查詢,而不使用 GraphQLObjectType
建立:
const schema = buildSchema(`
# 輸入型別 用 input 標識
input HeroInput {
name: String
age: Int
}
# 查詢型別
type Hero {
name: String
age: Int
}
type Mutation {
createHero(input: HeroInput): Hero
updateHero(hero: String!, input: HeroInput): Hero
}
# 需要至少定義一個 Query 不要GraphiQL會不顯示查詢
type Query {
hero: [Hero]
}
`)
複製程式碼
這邊案例有稍作修改
4. 實現新增資料和更新資料的邏輯
這邊處理新增資料和更新資料的邏輯,就要修改之前宣告的 root
的操作內容了:
const root = {
hero() {
return new Promise( (resolve, reject) => {
HeroModel.find((err, res) => {
if(err) {
reject(err)
return
}
resolve(res)
})
})
},
createHero({ input }) {
// 例項化一個Model
const { name, age } = input
const params = new HeroModel({ name, age })
return new Promise( (resolve, reject) => {
params.save((err, res) => {
if(err) {
reject(err)
return
}
resolve(res)
})
})
},
updateHero({ hero, input }) {
const { age } = input
return new Promise ((resolve, reject) => {
HeroModel.update({name: hero}, {age}, (err, res) => {
if(err) {
reject(err)
return
}
resolve(res)
})
})
}
}
複製程式碼
5. 模擬測試
最後我們在 GraphiQL
頁面上模擬測試一下,首先新增兩個英雄,鋼鐵俠和美國隊長,並設定他們的 age / name
屬性:
mutation {
createHero(input: {
name: "鋼鐵俠"
age: 40
}){
name
age
}
}
複製程式碼
mutation {
createHero(input: {
name: "美國隊長"
age: 20
}){
name
age
}
}
複製程式碼
頁面和介面沒有報錯,說明我們新增成功,資料庫中也有這兩條資料了:
在測試下查詢:
query {
hero {
name
age
}
}
複製程式碼
查詢也正常,接下來測試下更新,將美國隊長的 age
修改為 60:
mutation {
updateHero(hero: "美國隊長", input: {
age: 60
}){
age
}
}
複製程式碼
到這一步,我們也算是將這個練習做完了。
總結
-
GraphQL
是一種 API 的查詢語言,是 REST API 的替代品。 -
GraphQL
可以使用一個請求,獲取所有想要的資料。 -
建立查詢的方式有兩種:使用
buildSchema
或者GraphQLObjectType
。 -
查詢操作用
Query
,修改操作用Mutations
。 -
查詢型別用
type
,輸入型別用input
。
其實 GraphQL
還是很簡單好用的呢~~~
本文首發在 pingan8787個人部落格,如需轉載請保留個人介紹