GraphQL是什麼?

GraphQL 是由 Facebook 在 2012 年提出,並於 2015 年開源的一種API 資料查詢語言(Query Language for APIs),它讓前端可以用一種直覺、靈活的方式向後端請資料,只拿到自己需要的資料,不多也不少 Sample

GraphQL Schema

Schema是GraphQL裡面一個很重要的概念,定義了兩件事情

  1. 資料的結構與型別

    type Product {
      id: ID!
      name: String
      description: String
    }
    
  2. 有哪些方法可以使用(query, mutation , subscription)

    • query:查詢資料
    • mutation :異動資料 (包含INSERT,UPDATE, DELETE)
    • subscription:訂閱事件
    type Query {
      user(id: ID!): User
    }
    
    type Mutation {
      createPost(title: String!, content: String, authorId: ID!): Post
    }
    

Resolver

實際執行查詢、拿資料、組回傳格式,與Data Source溝通的地方,每個欄位都有自己對應的resolver

type Query {
  post(id: ID!): Post
}

type Post {
  id: ID!
  title: String
  author: User
}

type User {
  id: ID!
  name: String
}

const resolvers = {
  Query: {
    post: (_, { id }) => fetchPostById(id),
  },
  Post: {
    author: (parent) => fetchAuthor(parent.authorId),
  },
};

GraphQL實際做了什麼?

定義格式與查詢流程

格式

  • 系統提供哪些查詢或操作
  • 資料有哪些欄位,每個欄位的型別是什麼
  • 查詢時可以帶入哪些參數,輸入格式長什麼樣子

流程:

  • 定義查詢發生時,要怎麼執行,Resolver的執行順序,每個欄位背後都需要一個 Resolver,GraphQL 規定它們會從 parent 開始、一路遞迴呼叫子欄位的 Resolver

    query {
      post(id: 1) {
        title
        author {
          name
        }
      }
    }
    

⚠️ GraphQL只規範不實作,需要透過 GraphQL Server 工具去將規範給實現 常見的工具有:apollo server(Javascript), gqlgen(Go), Hasura等,可以根據語言和特性去選擇

GraphQL Server 的工作流程

Client端送出了request

query {
  user(id: 1) {
    name
    email
    posts {
      title
    }
  }
}
  1. 解析 Query 結構:首先,GraphQL Server 會解析前端送來的文字格式 Query,變成機器可操作的結構化資料

    Server 會解析出:

    項目 內容
    根操作類型 Query
    要查的資料型別 posts
    帶的參數 沒有
    要的欄位 id,content,author => 還需要下一層的資料(id,nickname,image)
  2. 驗證Query是否合法:

    • 型別驗證: 確認每個傳進來的參數,型別是否符合 Schema 定義
    • 欄位驗證: 確認 Query 裡要查詢的每個欄位,都必須事先在 Schema 中有定義
  3. 找到對應的 Resolver 函式

    Server 根據解析出來的 Query 結構,自動呼叫對應的 Resolver 函式,特別注意每一個field都可以對應到一個resolver,如果沒有特別設定的話,會使用預設的resolver也就是去找parent有沒有相同名稱field,如果有的話直接帶入

    • 解析第一層:查詢 posts ➔ Server 呼叫 posts 對應的 Resolver
    • 解析第二層:
      • post.id:沒有特別設定resolver,所以使用default resolver從上一層也就是parent的地方取得相同名稱的field來使用
      • post.content:同上
      • 查詢 author ➔Server 呼叫 post.author 對應的 Resolver
  4. 組成對應的schema:將posts的資訊,以及後續查詢的authors資訊,組合成Client預期的資料結構回傳