GraphQL 項目中的前端 mock 方案

image

在使用 GraphQL (以下簡稱 gql)的前端項目中,往往需要等待後臺同學定義好 Schema 並架設好 Playground 以後才能進行聯調。如果後臺同學阻塞了,前端只能被動等待。如果對於 gql 項目來說也能夠和 REST 一樣有一套 mock 方案就好了。經過一系列實踐,我選擇了 mocker-apiApollo 的方案來實現。

mocker-api

mocker-api 是一個基於 node 實現的接口 mock 工具(前身是webpack-api-mocker,依賴於 webpack-dev-server,現在可獨立運行)。由於我們的項目大都和 webpack 結合,所以這裏僅簡單介紹其與 webpack 結合的用法。

在 webpack 的 devServer 配置項中,引入以下內容:

devServer: {
  before (app) {
    require('mocker-api')(app, resolve('./mock/index.js'))
  }
}

這樣便完成了 webpack 和 mocker-api 的結合。接下來我們要到 /mock/index.js 裏面寫邏輯:

// /mock/index.js

module.exports = {
  'POST /api': (req, res) => {
    return res.send('Hello world')
  }
}

此時開啓 webpack-dev-server,在頁面中使用 POST 方式請求 /api,即可得到內容爲 Hello world 的響應。

Apollo

Apollo 是一套完整的 GraphQL 實現方案,支持多種語言的服務端和客戶端,在這裏我們主要使用 apollo-server 來搭建前端的 gql mock 服務。

/mock 目錄下新建 /gql 目錄,再往裏面分別建立 /resolvers 目錄,types 目錄和 index.js 入口文件。下面我們以一個”查詢書籍信息“的例子來講述這個 gql mock 服務是怎麼做的。

/types 目錄下新建 Books.js

const { gql } = require('apollo-server')

module.exports = gql`
"""
書籍
"""
type Book {
  id: ID!
  "標題"
  title: String
  "作者"
  author: String
}

type Query {
  books: [Book]
}

type Mutation {
  addBook(title: String, author: String): [Book]
}
`

接下來,在 /resolvers 目錄底下新建 Books.js

const books = [
  {
    id: parseInt(Math.random() * 10000),
    title: 'Harry Potter and the Chamber of Secrets',
    author: 'J.K. Rowling'
  },
  {
    id: parseInt(Math.random() * 10000),
    title: 'Jurassic Park',
    author: 'Michael Crichton'
  }
]

module.exports = {
  query: {
    books: () => books,
  },
  mutation: {
    addBook: (root, book) => {
      book.id = parseInt(Math.random() * 10000)
      books.push(book)
      return books
    }
  }
}

最後在入口文件 index.js 裏分別引入上面兩個文件:

const { ApolloServer } = require('apollo-server')

const typeDefs = [
  require('./types/Books')
]

const resolvers = {
  Query: {
    ...require('./resolvers/Books').query
  },
  Mutation: {
    ...require('./resolvers/Books').mutation
  }
}

const server = new ApolloServer({ typeDefs, resolvers })

server.listen().then(({ url }) => {
  console.log(`🚀 Apollo server ready at ${url}`);
})

運行 node ./mock/gql/index.js,即可在 localhost:4000 打開 Playground 進行調試了。

image

使用 mocker-api 把請求轉發到本地的 Playground

在實際的業務中,gql 接口往往被封裝成形如 /api/gql 的形式,和其他的 rest 接口一起供客戶端調用。爲了讓 /api/gql 接口能夠被轉發到 localhost:4000 的 Playground,我們可以利用 mocker-api 進行轉發。

改寫 /mock/index.js,爲其增加一個 /api/gql 的地址:

const axios = require('axios')

module.exports = {
  'POST /api': (req, res) => {
    return res.send('Hello world')
  },
  'POST /api/gql': async (req, res) => {
    const reqBody = req.body
    const { data: result } = await axios({
      url: 'http://localhost:4000',
      method: 'POST',
      data: reqBody
    }).catch(e => e)
    return res.send({
      data: result.data
    })
  }
}
這裏我使用了 axios 往 apollo-server 發起請求。

此時在 webpack-dev-server 所啓動的頁面中往 /api/gql 發起一個 gql 請求,即可驗證接口:

      fetch('/api/gql', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ query: 'query GetBooks {  books {    title  }}' })
      })
        .then(res => res.json())
        .then(result => console.log(result))

image

由於 mocker-api 支持 hot reload,所以當我們什麼時候不再需要 mock 數據時,直接在 /mock/index.js 中把 'POST /api/gql' 這一段註釋掉即可,無需重啓 dev server。

至此,GraphQL 項目中的前端 mock 方案大功告成。

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