GraphQL(1) - 簡介 & 語法


Posted by TempuraEngineer on 2022-10-27

目錄


GraphQL是甚麼

GraphQL是種資料庫查詢語言

其架構是由一個一個的type組成,type內定義了欄位

// type是型別宣告的關鍵字,Capsule則是型別名
type Capsule {
  // 內部是欄位、欄位的型別
  id: ID
  landings: Int
  missions: [CapsuleMission]
  original_launch: Date
  reuse_count: Int
  status: String
  type: String
  dragon: Dragon
}

優點

  1. 只拿需要的資料
  2. 極具彈性,資料間可以連來連去,且不像SQL的Join複雜
  3. 支援型別定義、偵錯,目前有5種預設型別,Int、Float、String、Boolean、ID(String | Int)

缺點

  1. 無論query是否成功都會得到HTTP code 200,使得難以處理error的情況
  2. 快取有困難
    官方提到可以用2種方法發request給GraphQL,GET與POST

    GET因為網址會帶query string,所以可快取

    只是網址可能會長成這樣,而且帶有變數的request並無法使用此方法

     // 一定要留空格,空格代表換行
     https://api.spacex.land/graphql/?query={ capsules { id missions { name flight } } }
    

    POST的話因為把query轉為JSON,並帶入body,所以response不會被cache

     async function bar(){
         const res = await fetch('https://api.spacex.land/graphql/', {
             method:'POST',
             body:JSON.stringify({query:"{\n  capsules {\n    id\n  }\n}\n", variables:null}),
             headers:{
                 "Content-Type":"application/json; charset=utf-8"
             }
         })
    
         return await res.json();
     }
    
     const {data} = await bar();
     console.log(data);
    

    關於GET與POST可以回顧這篇


語法

本文使用中的例子是GraphQL playground - space X來進行操作

它的schema滿完整的,只可惜使用的GraphQL版本低於5,故有些功能不能用


field & argument

field就是欄位,有甚麼欄位可以用Docs看

query是operation type,capsuleData是operation name,只有一組query時可以不寫,多組一定要寫,不然會發生衝突

先來看一下型別

// ()內的是argument,:後是型別
capsules(
    find: CapsulesFind
    limit: Int
    offset: Int
    order: String
    sort: String
): [Capsule]
// Capsule的欄位
id: ID
landings: Int
missions: [CapsuleMission]
original_launch: Date
reuse_count: Int
status: String
type: String
dragon: Dragon

語法

query capsuleData {
  capsules(limit:2) { // limit:2是argument,這代表只抓前2筆資料
    id
    missions {
      flight
      name
    }
  }
}


variable

// $id:ID是variable,ID是型別,!代表必填
query capsuleData($id:ID! = "C102"){ // = "C102"是給變數預設值
  capsule(id:$id){
    id
    missions {
      flight
      name
    }
  }
}

下方的Query Variable區域用JSON格式填寫變數

{
  "id":"C101"
}


aliases

和SQL的別名一樣都是為了避免同樣的field導致衝突

query capsuleData {
  C105Data: capsule(id: "C105") { // C105Data是別名
    id
    missions {
      flight
      name
    }
  }
  C101Data: capsule(id: "C101") {
    id
    missions {
      flight
      name
    }
  }
}


fragment

透過fragment建立field set,這可以用在同樣的欄位重複多次出現時(就像前個例子)

argument用於在一坨同型別的資料中根據條件撈資料

{
  // id: "C105"是argument
  leftComparison: capsule(id: "C105") { 
    ...comparisonFields
  }
  rightComparison: capsule(id: "C101") {
    ...comparisonFields
  }
}

// comparisonFields是fragment的名稱,Capsule是型別名
fragment comparisonFields on Capsule { 
  id
  missions {
    flight
    name
  }
}


指令 include

graphql-tools 5+才能用

query capsuleData($limit:Int, $isFligheShow:Boolean!){
  capsules(limit:$limit){
    id
    missions @include(if: $isFligheShow) {
      flight
      name
    }
  }
}


參考資料

GraphQL - queries
Serving over HTTP
GraphQL 入門:初次實作 Schema 與 Resolver
GraphQL 入門: 簡介 X 範例 X 優缺點
GraphQL 入門: Arguments, Aliases, Fragment 讓 Query 更好用 (進階 Query)
HTTP caching in GraphQL
Making GraphQL Requests using HTTP Methods

playgrounds

GraphQL playground - space X
GraphQL Playground Example
PoP API Demo


#graphql







Related Posts

N + 1 problem

N + 1 problem

Single Page Application 的應用

Single Page Application 的應用

後端資料庫欄位型態與實作 Cookie

後端資料庫欄位型態與實作 Cookie


Comments