在使用 GraphQL (如下簡稱 gql)的前端項目中,每每須要等待後臺同窗定義好 Schema 並架設好 Playground 之後才能進行聯調。若是後臺同窗阻塞了,前端只能被動等待。若是對於 gql 項目來講也可以和 REST 同樣有一套 mock 方案就行了。通過一系列實踐,我選擇了 mocker-api 加 Apollo 的方案來實現。javascript
mocker-api 是一個基於 node 實現的接口 mock 工具(前身是webpack-api-mocker
,依賴於 webpack-dev-server,如今可獨立運行)。因爲咱們的項目大都和 webpack 結合,因此這裏僅簡單介紹其與 webpack 結合的用法。前端
在 webpack 的 devServer
配置項中,引入如下內容:java
devServer: { before (app) { require('mocker-api')(app, resolve('./mock/index.js')) } }
這樣便完成了 webpack 和 mocker-api 的結合。接下來咱們要到 /mock/index.js
裏面寫邏輯:node
// /mock/index.js module.exports = { 'POST /api': (req, res) => { return res.send('Hello world') } }
此時開啓 webpack-dev-server,在頁面中使用 POST 方式請求 /api
,便可獲得內容爲 Hello world
的響應。webpack
Apollo 是一套完整的 GraphQL 實現方案,支持多種語言的服務端和客戶端,在這裏咱們主要使用 apollo-server 來搭建前端的 gql mock 服務。ios
在 /mock
目錄下新建 /gql
目錄,再往裏面分別創建 /resolvers
目錄,types
目錄和 index.js
入口文件。下面咱們以一個」查詢書籍信息「的例子來說述這個 gql mock 服務是怎麼作的。git
在 /types
目錄下新建 Books.js
:github
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
:web
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
裏分別引入上面兩個文件:json
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 進行調試了。
在實際的業務中,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))
因爲 mocker-api 支持 hot reload,因此當咱們何時再也不須要 mock 數據時,直接在 /mock/index.js
中把 'POST /api/gql'
這一段註釋掉便可,無需重啓 dev server。
至此,GraphQL 項目中的前端 mock 方案大功告成。