GraphQL介紹&使用nestjs構建GraphQL查詢服務

晁州發表於2018-02-08

GraphQL介紹&使用nestjs構建GraphQL查詢服務(文章底部附demo地址)

GraphQL一種用為你 API 而生的查詢語言。出自於Facebook,GraphQL非常易懂,直接看查詢語句就能知道查詢出來的資料是什麼樣的。本質上屬於API Layer層,負責前端請求的合併、資料整理等功能。

GraphQL介紹&使用nestjs構建GraphQL查詢服務

查詢示例

使用幾個簡單的例子看下GraphQL的查詢是什麼樣子的。

普通查詢

{
  me {
    name
  }
}

查詢出來的資料格式如下:

{
  "me": {
    "name": "wanghao"
  }
}

1、返回來的資料是一個json
2、返回資料格式和查詢完全一致

帶引數的巢狀查詢

入參格式:

{
  user(id: 6) {
    name,
    profilePicture {
      width,
      height,
      url
    }
  }
}

查詢出來的資料如下:

{
  "me" {
    "name": "wanghao,"
    "profilePicture": {
      "width": 50,
      "height": 50,
      "url": "https://cdn/some.jpg"
    }
  }
}

當然,profilePicture查詢時也可以指定引數:

{
  me {
    name,
    profilePicture(size: 300) {
      width,
      height,
      url
    }
  }
}

輸出可能如下:

{
  "me" {
    "name": "wanghao,"
    "profilePicture": {
      "width": 300,
      "height": 300,
      "url": "https://cdn/300.jpg"
    }
  }
}

指定別名查詢

有時候同一欄位我們想要查詢兩次,但是兩次指定的引數不同,比如一個使用者有多張頭像,我們只想查詢其中的2張,可以如下:

{
  me {
    name,
    littlePic: profilePicture(size: 50) {
      width,
      height,
      url
    },
    bigPic: profilePicture(size: 300) {
      width,
      height,
      url
    }
  }
}

輸出結果如下:

{
  "me" {
    "name": "wanghao,"
    "littlePic": {
      "width": 50,
      "height": 50,
      "url": "https://cdn/50.jpg"
    },
    "bigPic": {
      "width": 300,
      "height": 300,
      "url": "https://cdn/300.jpg"
    }
  }
}

更多查詢請參考:http://graphql.cn/learn/queries/

變更

查詢只適用於資料查詢,但是往往介面還有部分新增、修改、刪除操作,這個時候就需要使用變更(Mutations)。

想要新增一條資料,簡單的變更入參如下:

mutation($inputComment: CommentInput!) {
  addComment(data: $inputComment)
}

其中$inputComment是GraphQL中的變數寫法,具體如下:

{
  "inputComment": {
    "postId": "5a796104fe9b131a10d9627d",
    "text": "測試評論部分23232"
    }
}

返回資料直接如下:

{
  "data": {
    "addComment": true
  }
}

實際請求時的資料格式

GraphQL請求時不限制get、post請求,如果是get,會自動將請求體放在query中,看下實際請求時入參是什麼樣子的:

{
    query: "mutation($inputComment: CommentInput!) {↵  addComment(data: $inputComment)↵}↵↵"
    variables: "{↵  "inputComment": {↵"postId":"5a796104fe9b131a10d9627d",↵"text":"測試評論部分23232"↵}"
}

可以看出,請求時實際傳送的是一串字串至GraphQL伺服器,GraphQL伺服器會自動解析該字串內容。

GraphQL視覺化查詢工具

GraphQL的所有實現基本都有實現該視覺化工具,進行簡單配置即可檢視,express-graphql模組配置如下:

// GraphqQL server route
app.use('/graphql', graphqlHTTP(req => ({
  schema,
  pretty: true,         // 配置顯示pretty按鈕進行程式碼美化
  graphiql: true,       // 配置開啟視覺化查詢
})));

GraphQL介紹&使用nestjs構建GraphQL查詢服務

GraphQL介紹&使用nestjs構建GraphQL查詢服務

GraphQL介紹&使用nestjs構建GraphQL查詢服務

dataloader

N+1查詢問題

# 定義
type User {
  name: String,
  friends: [User]
}

#查詢
{
  users {
    name
    friends {
      name
      friends {
        name
      }
    } 
  }
}

GraphQL支援巢狀查詢,如果沒有dataloader,就會出現嚴重的N+1查詢效能問題。

Dataloader(官方網址)是由facebook推出,能大幅降低資料庫的訪問頻次,經常在Graphql場景中使用。

GraphQL介紹&使用nestjs構建GraphQL查詢服務

import Sequelize from 'sequelize'
import DataLoader from 'dataloader'

// 定義表結構
const sequelize = new Sequelize('test', null, null, {
        dialect: 'sqlite',
    })
const UserModel = sequelize.define('user', {
    name: Sequelize.STRING
})
await sequelize.sync({force: true})

//插入測試資料
await [
    UserModel.create({name: 'ron'}),
    UserModel.create({name: 'john'}),
]

// 初始化DataLoader,傳入一個批處理函式
const userLoader = new DataLoader(keys => UserModel.findAll({where: {name: {$in: keys}}})) 

// 以下2個Load語句會被自動批處理,合併成一次資料庫的操作
await [
    userLoader.load('ron'),
    userLoader.load('john')
]
Executing (default): SELECT id, name, createdAt, updatedAt FROM users AS user WHERE user.name IN ('ron', 'john’);

DataLoader快取的典型應用是per-request範圍的快取,不能取代redis等應用級別的快取。

使用nestjs構建GraphQL Server服務

nestjs,官網地址:https://docs.nestjs.com,是一個使用typescript構建nodejs後端應用的框架,類似java中的spring框架:依賴注入、攔截器、過濾器、裝飾器模式等等,比較看好。

使用nestjs搭配GraphQL、typeorm、mysql實現了一個簡單的GraphQL查詢服務,查詢支援單個查詢、列表查詢、關聯查詢,變更支援修改、刪除操作,具體demo地址: https://github.com/caiya/graphql-nestjs-typeorm

相關文章