前端有了這兩樣神器,再也不用追著後臺要介面啦
阿新 • • 發佈:2020-12-04
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215551343-599903765.png)
> DevUI是一支兼具設計視角和工程視角的團隊,服務於華為雲[DevCloud](https://www.huaweicloud.com/devcloud/)平臺和華為內部數箇中後臺系統,服務於設計師和前端工程師。
> 官方網站:[devui.design](https://devui.design/)
> Ng元件庫:[ng-devui](https://github.com/DevCloudFE/ng-devui)(歡迎Star)
> 官方交流群:新增DevUI小助手(微訊號:devui-official)
> DevUIHelper外掛:[DevUIHelper-LSP](https://github.com/sspku-yqLiu/DevUIHelper-LSP)(歡迎Star)
前言
--
之前發過一個沸點,聊到前端為了提升業務交付效率,有必要去除對上游的依賴,這次想給大家分享下我自己在去後臺依賴方面的一些實踐,歡迎大家一起討論!
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215641371-977374547.png)
前端依賴後臺什麼?
---------
在整個研發鏈路上,後臺的定位是給前端提供高效、穩定的API介面,前端通過這些API去獲取需要的資料,並展示給使用者。
所以要去除對後臺的依賴,前端就需要自己模擬這些介面,並構造相應的測試資料。
怎麼模擬後臺介面?
---------
為了在前端模擬後臺介面,我給大家介紹第一件神器:[JSON Server](https://github.com/typicode/json-server)。
以下是JSON Server官方對自己的定位:
> Get a full fake REST API with zero coding in less than 30 seconds (seriously)
> 無需寫程式碼,在30秒內獲得完整的REST API。
以我現在負責的[DevCloud](https://www.huaweicloud.com/devcloud/)業務——[XBoard看板](https://support.huaweicloud.com/usermanual-projectman/devcloud_hlp_00021.html)專案——舉栗子,有一個介面是獲取某個看板下面的所有卡片資訊(只保留關鍵欄位),介面基本協議如下(介面協議提前跟後臺協商好):
```text
GET /v1/[projectid]/[boardid]/cards
{
"error": null,
"status": "success",
"result": [
{
"column_id": "7c489b6746fe4329aa8c869f4c13fab5",
"card_list": [
{
"id": "4634045604195569664", // 卡片ID
"subject": "任務已ready,準備啟動開發的任務", // 卡片主題
"sequence": "11203427", // 卡片序列號
"index": "12", // 序號(用於拖動排序)
"archived": false, // 是否已歸檔
"blocked": false, // 是否設定阻塞
"is_parent": false, // 是否父卡片
"createdOn": "1598238210463", // 建立時間
"updatedOn": "1598238210463", // 最近更新時間
"parent": { // 父卡片
"subject": "設計完成,正在進行開發的需求",
"id": "4634045604190851072"
},
"board": { // 卡片所在的看板
"id": "1661625c5f72471a81979482ab148066",
"name": "開發"
},
"column": { // 狀態列
"id": "7c489b6746fe4329aa8c869f4c13fab5",
"name": "就緒",
"type": "READY",
"deleted": false
},
"card_type": { // 卡片型別
"color": "#6CBFFF",
"name": "任務",
"icon": "icon-op-task",
"id": "2"
},
"author": { // 卡片作者
"name": "kagolzeng",
"id": "05329882ba000f711ffec00c21191097",
"nick_name": "kagol",
"gender": "male"
},
"updater": { // 最近更新者
"name": "kagolzeng",
"id": "05329882ba000f711ffec00c21191097",
"nick_name": "kagol",
"gender": "male"
}
},
... // 其他卡片
]
},
... // 其他狀態列
]
}
```
這個介面怎麼用JSON Server模擬呢?
只需要以下4步(假設已經有專案工程,比如:[NG CLI](https://cli.angular.io/)工程):
* 第1步:安裝JSON Server
* 第2步:配置測試資料
* 第3步:編寫啟動指令碼命令
* 第4步:啟動Mock服務
我們一步一步來搭建一個Mock服務:
第1步:安裝JSON Server
-----------------
在專案根目錄下執行以下命令:
```text
npm i -D json-server
```
第2步:配置測試資料
----------
在專案根目錄下新建db.json檔案,加上之前已經跟後臺定好的介面資料(為避免重複,已省略部分欄位):
```text
{
"result": [
{
"column_id": "7c489b6746fe4329aa8c869f4c13fab5",
"card_list": [
{
"id": "4634045604195569664", // 卡片ID
"subject": "任務已ready,準備啟動開發的任務", // 卡片主題
"board": { // 卡片所在的看板
"id": "1661625c5f72471a81979482ab148066",
"name": "開發"
},
"column": { // 狀態列
"id": "7c489b6746fe4329aa8c869f4c13fab5",
"name": "就緒",
"type": "READY",
"deleted": false
},
"card_type": { // 卡片型別
"color": "#6CBFFF",
"name": "任務",
"icon": "icon-op-task",
"id": "2"
}
}
]
}
]
}
```
第3步:編寫啟動指令碼命令
------------
只需要在package.json的scripts中編寫Mock服務的啟動指令碼即可:
```text
"mock": "node_modules/.bin/json-server --watch db.json --port 9090"
```
第4步:啟動Mock服務
------------
```text
npm run mock
```
啟動之後控制檯顯示:
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215707672-762885155.png)
在瀏覽器位址列輸入:[http://localhost:9090/cards](http://localhost:9090/cards),即可檢視該介面的返回資料
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215717681-517700122.png)
如何構造測試資料?
---------
大家發現以上模擬後臺介面的方式有什麼問題了沒?
測試資料的構造太麻煩!
如果每個介面的返回資料都需要一個一個去構造,至少會有兩個問題:
* 一是每條記錄都自己手寫,太累,資料也太死;
* 二是想要模擬大量的資料很難,且會導致專案原始檔體積變大。
為了解決以上問題,我要給大家介紹第二件神器:[Mock.js](http://mockjs.com/)。
Mock.js對自己的定位是:
> 生成隨機資料,攔截 Ajax 請求
Mock.js可以生成幾乎任何你能想到的資料型別,比如數字、字元、布林值、日期、顏色、圖片、地址、URL、名字、標題、段落等,甚至還支援正則表示式。
將Mock.js整合進來也只需要簡單的3個步驟:
* 第1步:修改JSON Server配置
* 第2步:修改指令碼命令
* 第3步:重啟Mock服務
第1步:修改JSON Server配置
-------------------
為了整合Mock.js,我們需要將之前的db.json改成db.js,並增加routes.json檔案,可以將這兩個檔案放到根目錄下的mock資料夾下。
```text
mock/db.js
var Mock = require('mockjs');
const CARDS = Mock.mock({
"error": null,
"status": "success",
"result|10": [{ // 生成10個狀態列
"column_id": "@guid",
"card_list|20": [{ // 狀態列下有20張卡片
"id": "@guid", // 卡片ID
"subject": '@title', // 卡片主題
"sequence": /d{8}/, // 卡片序列號
"index": "@integer(1, 100)", // 序號(用於拖動排序)
"archived": "@boolean", // 是否已歸檔
"blocked": "@boolean", // 是否設定阻塞
"is_parent": "@boolean", // 是否父卡片
"createdOn": "@date", // 建立時間
"updatedOn": "@date", // 最近更新時間
"parent": { // 父卡片
"id": "@guid",
"name": "@cword(2,10)"
},
"board": { // 卡片所在的看板
"id": "@guid",
"name": "@cword(2,10)"
},
"column": { // 狀態列
"id": "@guid",
"name": "@cword(2,10)",
"type": "@string('upper', 2, 20)",
"deleted": "@boolean"
},
"card_type": { // 卡片型別
"color": "@color",
"name": "@cword(2,10)",
"icon": /icon-[a-z]-{1-3}/,
"id": "@integer(1, 100)"
},
"author": { // 卡片作者
"name": "@name",
"id": "@guid",
"nick_name": "@name",
"gender": "@string('lower', 4)"
},
"updater": { // 最近更新者
"name": "@name",
"id": "@guid",
"nick_name": "@name",
"gender": "@string('lower', 4)"
}
}]
}]
});
const API = () => ({
'cards': CARDS,
});
module.exports = API;
```
```text
mock/routes.json
{
"/cards": "/cards"
}
```
第2步:修改指令碼命令
----------
指令碼命令也需要做相應的修改
```text
"mock": "node_modules/.bin/json-server --watch mock/db.js --routes mock/routes.json --port 9090"
```
第3步:重啟Mock服務
------------
這時我們重新使用:
```text
npm run mock
```
命令啟動Mock服務,在瀏覽器中輸入
[http://localhost:9090/cards](http://localhost:9090/cards)
訪問/cards介面:
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215739657-1304380533.png)
可以看到Mock.js為我們生成了非常多隨機測試資料,之前構造這些資料可是要費很大的工夫。
並且為了構造這大量的測試資料,我們只是在db.js中增加了不到50行程式碼,不用在擔心原始檔體積太大的問題。
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215751152-132817809.png)
是不是非常便捷?
讓我們一起來試試業務中如何使用這些Mock介面,以及如何無縫切換成真實的後臺介面吧。
一起來試試看吧
-------
假設我們已經用NG CLI建立了一個專案,為了呼叫Mock介面,我們需要引入Angular的HttpClientModule模組:
```text
src/app/app.module.ts
import { HttpClientModule } from '@angular/common/http';
imports: [
...,
HttpClientModule
]
```
直接呼叫Mock服務介面
------------
然後注入Angular的HttpClient服務,就可以向Mock服務的/cards介面發起請求:
```text
src/app/app.component.ts
import { HttpClient } from '@angular/common/http';
constructor(
private http: HttpClient
) {}
ngOnInit() {
this.http.get('http://localhost:9090/cards').subscribe(cards => {
console.log('cards:', cards);
});
}
```
獲取到的介面資料如下:
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215805696-1712293337.png)
使用代理無縫切換後臺介面
------------
聰明的你肯定發現直接呼叫Mock服務的介面有問題:部署到測試環境或者現網怎麼辦?
因為環境上呼叫的肯定是相應環境的後臺介面,而不是Mock服務的介面,所以在本地開發時將介面代理到Mock服務,實際呼叫介面時不加具體的域名資訊。
實際呼叫介面應該是以下的方式:
```text
this.http.get('/v1/cards').subscribe(cards => {
console.log('cards:', cards);
});
```
為了做到無縫切換後臺介面,即:無需修改任何程式碼,本地呼叫Mock服務介面,線上呼叫後臺介面。
我們需要在本地開發時將介面代理到Mock服務,可以使用NG CLI提供代理配置proxyConfig:
```text
angular.json
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ng-demo:build",
"port": 4600,
"proxyConfig": "proxy.config.js" // 新增代理配置
},
...
}
```
代理配置檔案:
```text
proxy.config.js
const PROXY_CONFIG = {
'/v1': {
target: 'http://localhost:9090/v1'
}
};
module.exports = PROXY_CONFIG;
```
我們的Mock服務不需要做任何改變。
其他框架配置代理
--------
如果你使用的不是NG CLI,要怎麼配置代理呢?
### Vue CLI配置代理
```text
vue.config.js
devServer: {
proxy: {
'/v1': {
target: 'http://localhost:9090/v1'
}
}
}
```
### Webpack配置代理
Webpack的寫法和Vue CLI的差不多
```text
webpack.config.js
devServer: {
proxy: {
'/v1': {
target: 'http://localhost:9090/v1'
}
}
}
```
### CreateReactApp配置代理
React稍微麻煩一點兒,需要安裝http-proxy-middleware中介軟體。
```text
const proxy = require("http-proxy-middleware");
module.exports = function(app) {
app.use(
proxy("/api/", {
target: "http://localhost:9090/v1"
})
);
};
```
增加TS型別
------
如果你的專案使用TypeScript的話,一般都會給介面資料增加TS型別,我給大家介紹一個根據介面自動生成TS型別檔案的神器:[quicktype](https://github.com/quicktype/quicktype)。
quicktype的定位是:
> Generate types and converters from JSON, Schema, and GraphQL.
> 從JSON、Schema和GraphQL生成型別和轉換器。
剛才我們已經啟動了我們的Mock服務,在瀏覽器位址列輸入[http://localhost:9090/cards](http://localhost:9090/cards),也可以檢視/cards介面的返回資料,這時我們可以使用quicktype工具根,據介面地址生成相應的TS型別檔案。
只需要2步即可:
* 第1步:安裝quicktype
* 第2步:生成TS型別檔案
第1步:安裝quicktype
---------------
```text
npm i -g quicktype
```
第2步:生成TS型別檔案
------------
```text
quicktype http://localhost:9090/cards -o ./src/app/shared/types/card.interface.ts --runtime-typecheck
```
使用TS型別
------
```text
import { CardInterface } from './shared/types/card.interface';
this.http.get('/v1/cards').subscribe((cards: CardInterface) => {
console.log('cards:', cards);
});
```
使用TS型別有兩個顯而易見的好處:
一是型別校驗和自動提示;
二是資料文件化和欄位自動提醒和補齊。
型別校驗和自動提示:
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215822763-1383905656.png)
資料文件化和欄位自動提醒和補齊:
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215828281-292554243.png)
小結
--
本文主要介紹如何通過JSON Server和Mock.js兩大神器,在前端搭建Mock服務,模擬後臺介面,從而在開發階段去除對後臺的依賴,提升業務交付的效率。
歡迎大家評論交流!
原始碼地址:[https://github.com/kagol/ng-mock-server](https://github.com/kagol/ng-mock-server)
加入我們
----
我們是DevUI團隊,歡迎來這裡和我們一起打造優雅高效的人機設計/研發體系。招聘郵箱:[email protected]。
文/Kagol
往期文章推薦
[《使用Git,10件你可能需要“反悔”的事》](https://www.cnblogs.com/kagol/p/14076276.html)
[《手把手教你使用Vue/React/Angular三大框架開發Pagination分頁元件》](https://www.cnblogs.com/kagol/p/14071347.html)
[《現代富文字編輯器Quill的內容渲染機制》](https://www.cnblogs.com/kagol/p/14063753.html)
附錄:XBoard看板專案一覽
---------------
[XBoard專案](https://support.huaweicloud.com/usermanual-projectman/devcloud_hlp_00021.html)的開發看板
![](https://img2020.cnblogs.com/blog/296720/202012/296720-20201203215845356-977270