GraphQL 入門 爲什麼要使用GraphQL 核心概念 生態以及工具 如何使用 參考資料

爲什麼要使用GraphQL

GraphQL是由Facebook團隊在2015年開源推出的一套用於替代傳統的REST API的框架。利用它能夠大幅提升開發效率以及應用性能。設想這樣一個場景:

你想要獲得一個用戶的朋友的國家信息,如果你使用的是REST API的話,你可能需要同時調用以下這些接口:

  • /users/{userName}/friends: 返回類似 {id: 1, name: 'xxx', friends: [2,3,4] }的結構
  • /friends/{ID}: 返回類似{id: 2, name: 'xxx', country: 23}的結構
  • /countries/{ID}: 返回類似{id: 23, name: 'China', flag: 'xxx', language: 'Chinese'}的信息

先取回以scq000爲用戶名的朋友id,然後利用這些返回的用戶id再查詢詳細的信息,最後再拼裝成想要的數據結構。你會發現,隨着應用複雜度的提升,API的數量以及請求的數量成倍地增加,客戶端爲了想要獲得一個簡單的數據信息,要往返多次地調用不同的API。

而GraphQL的出現就是爲了解決上述這些問題的,它本質上是一門面向API的查詢語言(Query Language for API)。可以根據客戶端想要的數據,一次性地將數據取回來。

比如,上面的這個例子就能用下面的Graph 請求來描述:

{
    user {
        friend {
            name
            country
        }
    }
}

然後返回的數據是像這樣:

{
    "user": {
        "friend": {
            "name": "scq000",
            "country": "China"
        }
    }
}

同時目前GraphQL也支持各種語言,對於主流的編程語言都有良好地支持,生態環境也搭建地不錯。國外的大公司,如facebook, paypal, twitter, github等現在都在項目中大量使用GraphQL。

核心概念

GraphQL中一個核心的概念就是Schema, 它是客戶端和服務端之間進行溝通的協議,定義好對應的數據schema後,前後端就可以獨立地進行開發,從而提高效率。

一個schema是由query和mutation兩部分組成的,如:

schema {
    query: Query,
    mutation: Mutation
}

其中, query對應的就是請求數據的對象,而mutation主要負責進行副作用,如create, delete, update等操作。

types

一個GraphQL schema中最基本的組件是對象類型,可以用來表示能從服務器獲取什麼類型的對象。GraphQL內置的標量數據類型(Scalar Types)有以下幾種:

  • Int: a signed 32bit 帶符號的32位整數

  • Float: 有符號雙精度浮點型

  • String: UTF-8編碼的字符串

  • Boolean: 布爾型,true和false兩個值

  • ID: 唯一標識符,用以重新獲取對象或作爲緩存的鍵

還有枚舉類型enum:

enum Country {
  CHINA
  JAPAN
  AMERICAN  
}

默認情況下每一個內置類型的都可以被設置成null,如果需要確保某個字段不爲空,需要使用!符號:

type Author {
    id: ID!
    firstName: string,
    courses: [String]
}

注意到courses的類型是[String],這表示這個字段是個數組類型。

除了使用內置類型外,還可以自定義類型:

type Query {
    author_details: [Author]
}

type Mutation {
    addAuthor(firstName: String, lastName: sring): Author
}

Queries

Fields

字段是Query對象上最基本的組成單位,服務端和客戶端的結構基本相同:

{
    viewer {
        name
    }
}

Arguments

在GrahQL中,你可以給字段傳遞參數。這樣可以避免重複的API請求,如下所示:

{
    followers (last: 3) {
        nodes {
            id
        }
    }
}

這表示請求最後3個記錄,你還可以使用:

{
    author (id: "1000") {
        name
        age
    }
}

這表示請求id爲1000的記錄。

alias

由於在請求中不能使用不同的參數來請求相同的字段,因此就需要使用alias來給字段起別名:

{
    firstFollowers: followers (first: 3) {
        nodes {
            id
            name
        }
        
    }
    lastFollowers: followers (last: 3) {
        nodes {
            id
            name
        }
    }
}

Fragments

片段(Fragment)是可複用的單位,可以讓你在多個Query對象中利用同一個Fragments:

{
    nodes {
        ...userInfo
    }
}

fragment userInfo on User {
    id
    bio
}

fragment關鍵字聲明一個片段對象,然後再使用的時候直接利用擴展運算符...就可以了。

Operation name

我們一般在聲明查詢對象的時候都是用簡寫形式省略query關鍵字和查詢名稱,不過如果需要減少代碼歧義,則需要顯式聲明:

query ViewerInfo {
    viewer {
        name
        date
    }
}

Variables

字段的參數可以是動態的,所以使用變量進行控制:

query ViewerInfo($isOwner: Boolean!) {
    viewer {
        id
        name
        start(ownedBy)
    }
}
{
    isOwner: false
}

Mutations

用來更新數據的(create, update, delete)的副作用。

Query的時候所有的查詢是同時執行的,但是Mutation操作是按順序執行的:

mutation NewStatus($input: ChangeUserStatusINput!) {
    changeUserStatus(input: $input) {
        clientMutationId
        status {
            message
        }
    }
}

生態以及工具

整個GraphQL架構是有客戶端和服務端兩部分組成中,其中客戶端主要負責處理數據請求的狀態管理,緩存,分頁,錯誤處理以及schema的校驗等工作。而服務端主要和數據庫打交道, 有schema 和resolvers, resolver主要處理業務邏輯。

現在比較主流的GraphQL客戶端框架有Apollo ClientRelay

服務端可以使用Apollo Server, express graphql, graphql yoda等。

數據庫方面可以使用Prisma, 是替代傳統的ORM框架的方案,支持多種數據庫。

最後再推薦一些其他有用的工具:

https://graphql.org/swapi-graphql/

graphql voyager: 圖示,模型設計的工具

graphql faker: mock 數據

graphql visual editor: 可視化編輯器

如何使用

最後,我們來寫一個實際的demo來應用一下GraphQL:

首先我們要先來定義一下schema對象:

import {
    GraphQLSchema,
    GraphQLObjectType,
    GraphQLInt
} from "graphql";

let counter = 1;

let schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'Query',
        fields: () => ({
            counter: {
                type: GraphQLInt,
                resolve: () => counter
            }
        })
    }),
    mutation: new GraphQLObjectType({
        name: "Mutation",
        fields: () => ({
            incrementCounter: {
                type: GraphQLInt,
                resolve: () => ++counter
            }
        })
    })
})

這裏定義了一個counter的字段,然後mutation裏有一個incrementCounter的方法,每次執行這個mutation,都會讓counter的值加1。

有了schema後,接着就可以利用express來開啓一個叫做/graphql的接口,並使用已經定義好的schema:

const app = express();
const port = 3000

app.use('/graphql', GraphQLHTTP({
    schema
}));

app.listen(port, () => console.log(`Example app listening on port ${port}`))

最後我們就可以直接在瀏覽器中輸入localhost:3000/graphql使用了

參考資料

https://graphql.org/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章