• 前端有了这两样神器,再也不用追着后台要接口啦


    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师。
    官方网站:devui.design
    Ng组件库:ng-devui(欢迎Star)
    官方交流群:添加DevUI小助手(微信号:devui-official)
    DevUIHelper插件:DevUIHelper-LSP(欢迎Star)

    前言

    之前发过一个沸点,聊到前端为了提升业务交付效率,有必要去除对上游的依赖,这次想给大家分享下我自己在去后台依赖方面的一些实践,欢迎大家一起讨论!

    前端依赖后台什么?

    在整个研发链路上,后台的定位是给前端提供高效、稳定的API接口,前端通过这些API去获取需要的数据,并展示给用户。

    所以要去除对后台的依赖,前端就需要自己模拟这些接口,并构造相应的测试数据。

    怎么模拟后台接口?

    为了在前端模拟后台接口,我给大家介绍第一件神器:JSON Server

    以下是JSON Server官方对自己的定位:

    Get a full fake REST API with zero coding in less than 30 seconds (seriously)
    无需写代码,在30秒内获得完整的REST API。

    以我现在负责的DevCloud业务——XBoard看板项目——举栗子,有一个接口是获取某个看板下面的所有卡片信息(只保留关键字段),接口基本协议如下(接口协议提前跟后台协商好):

    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工程):

    • 第1步:安装JSON Server
    • 第2步:配置测试数据
    • 第3步:编写启动脚本命令
    • 第4步:启动Mock服务

    我们一步一步来搭建一个Mock服务:

    第1步:安装JSON Server

    在项目根目录下执行以下命令:

    npm i -D json-server
    

    第2步:配置测试数据

    在项目根目录下新建db.json文件,加上之前已经跟后台定好的接口数据(为避免重复,已省略部分字段):

    {
      "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服务的启动脚本即可:

    "mock": "node_modules/.bin/json-server --watch db.json --port 9090"
    

    第4步:启动Mock服务

    npm run mock
    

    启动之后控制台显示:

    在浏览器地址栏输入:http://localhost:9090/cards,即可查看该接口的返回数据

    如何构造测试数据?

    大家发现以上模拟后台接口的方式有什么问题了没?

    测试数据的构造太麻烦!

    如果每个接口的返回数据都需要一个一个去构造,至少会有两个问题:

    • 一是每条记录都自己手写,太累,数据也太死;
    • 二是想要模拟大量的数据很难,且会导致项目源文件体积变大。

    为了解决以上问题,我要给大家介绍第二件神器:Mock.js

    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文件夹下。

    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;
    
    mock/routes.json
    
    {
      "/cards": "/cards"
    }
    

    第2步:修改脚本命令

    脚本命令也需要做相应的修改

    "mock": "node_modules/.bin/json-server --watch mock/db.js --routes mock/routes.json --port 9090"
    

    第3步:重启Mock服务

    这时我们重新使用:

    npm run mock
    

    命令启动Mock服务,在浏览器中输入

    http://localhost:9090/cards

    访问/cards接口:

    可以看到Mock.js为我们生成了非常多随机测试数据,之前构造这些数据可是要费很大的工夫。

    并且为了构造这大量的测试数据,我们只是在db.js中增加了不到50行代码,不用在担心源文件体积太大的问题。

    是不是非常便捷?

    让我们一起来试试业务中如何使用这些Mock接口,以及如何无缝切换成真实的后台接口吧。

    一起来试试看吧

    假设我们已经用NG CLI创建了一个项目,为了调用Mock接口,我们需要引入Angular的HttpClientModule模块:

    src/app/app.module.ts
    
    import { HttpClientModule } from '@angular/common/http';
    
    imports: [
      ...,
      HttpClientModule
    ]
    

    直接调用Mock服务接口

    然后注入Angular的HttpClient服务,就可以向Mock服务的/cards接口发起请求:

    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);
      });
    }
    

    获取到的接口数据如下:

    使用代理无缝切换后台接口

    聪明的你肯定发现直接调用Mock服务的接口有问题:部署到测试环境或者现网怎么办?

    因为环境上调用的肯定是相应环境的后台接口,而不是Mock服务的接口,所以在本地开发时将接口代理到Mock服务,实际调用接口时不加具体的域名信息。

    实际调用接口应该是以下的方式:

    this.http.get('/v1/cards').subscribe(cards => {
      console.log('cards:', cards);
    });
    

    为了做到无缝切换后台接口,即:无需修改任何代码,本地调用Mock服务接口,线上调用后台接口。

    我们需要在本地开发时将接口代理到Mock服务,可以使用NG CLI提供代理配置proxyConfig:

    angular.json
    
    "serve": {
      "builder": "@angular-devkit/build-angular:dev-server",
      "options": {
        "browserTarget": "ng-demo:build",
        "port": 4600,
        "proxyConfig": "proxy.config.js" // 新增代理配置
      },
      ...
    }
    

    代理配置文件:

    proxy.config.js
    
    const PROXY_CONFIG = {
      '/v1': {
        target: 'http://localhost:9090/v1'
      }
    };
    
    module.exports = PROXY_CONFIG;
    

    我们的Mock服务不需要做任何改变。

    其他框架配置代理

    如果你使用的不是NG CLI,要怎么配置代理呢?

    Vue CLI配置代理

    vue.config.js
    
    devServer: {
      proxy: {
        '/v1': {
          target: 'http://localhost:9090/v1'
        }
      }
    }
    

    Webpack配置代理

    Webpack的写法和Vue CLI的差不多

    webpack.config.js
    
    devServer: {
      proxy: {
        '/v1': {
          target: 'http://localhost:9090/v1'
        }
      }
    }
    

    CreateReactApp配置代理

    React稍微麻烦一点儿,需要安装http-proxy-middleware中间件。

    const proxy = require("http-proxy-middleware");
    
    module.exports = function(app) {
      app.use(
        proxy("/api/", {
          target: "http://localhost:9090/v1"
        })
      );
    };
    

    增加TS类型

    如果你的项目使用TypeScript的话,一般都会给接口数据增加TS类型,我给大家介绍一个根据接口自动生成TS类型文件的神器:quicktype

    quicktype的定位是:

    Generate types and converters from JSON, Schema, and GraphQL.
    从JSON、Schema和GraphQL生成类型和转换器。

    刚才我们已经启动了我们的Mock服务,在浏览器地址栏输入http://localhost:9090/cards,也可以查看/cards接口的返回数据,这时我们可以使用quicktype工具根,据接口地址生成相应的TS类型文件。

    只需要2步即可:

    • 第1步:安装quicktype
    • 第2步:生成TS类型文件

    第1步:安装quicktype

    npm i -g quicktype
    

    第2步:生成TS类型文件

    quicktype http://localhost:9090/cards -o ./src/app/shared/types/card.interface.ts --runtime-typecheck
    

    使用TS类型

    import { CardInterface } from './shared/types/card.interface';
    
    this.http.get('/v1/cards').subscribe((cards: CardInterface) => {
      console.log('cards:', cards);
    });
    

    使用TS类型有两个显而易见的好处:

    一是类型校验和自动提示;

    二是数据文档化和字段自动提醒和补齐。

    类型校验和自动提示:

    数据文档化和字段自动提醒和补齐:

    小结

    本文主要介绍如何通过JSON Server和Mock.js两大神器,在前端搭建Mock服务,模拟后台接口,从而在开发阶段去除对后台的依赖,提升业务交付的效率。

    欢迎大家评论交流!

    源码地址:https://github.com/kagol/ng-mock-server

    加入我们

    我们是DevUI团队,欢迎来这里和我们一起打造优雅高效的人机设计/研发体系。招聘邮箱:muyang2@huawei.com。

    文/Kagol

    往期文章推荐

    《使用Git,10件你可能需要“反悔”的事》

    《手把手教你使用Vue/React/Angular三大框架开发Pagination分页组件》

    《现代富文本编辑器Quill的内容渲染机制》

    附录:XBoard看板项目一览

    XBoard项目的开发看板

  • 相关阅读:
    用原生PHP做Blog系统-Day01
    PHP做猜数字游戏
    关于html头部引用(meta,link)
    gulp基本入门
    前端构建工具gulpjs的使用介绍及技巧
    $.ajax()方法详解 jquery中的ajax方法
    js string 转 int 注意的问题——parseInt
    经常玩电脑怎么防辐射
    js 禁止重复提交
    jquery 监听回车提交
  • 原文地址:https://www.cnblogs.com/kagol/p/14083230.html
Copyright © 2020-2023  润新知