Develop a tool that generates interface files automatically and mocks them

Pain points are:

  1. Write interface API file (as follows), more trouble. Most of the interfaces are in the same format, either GET or POST. I’m doing it over and over again.
    • Following the DRY (Don’t Repeat Yourself) principle, we tried to automate this
    // This is an API file that needs to be written repeatedly each time
    
    import { axios } from './myAxios.js'
    
    export const xxxxList = (data) = > {
      return axios({
        method: 'post'.url: '/xxx/xxx',
        data
      })
    }
    
    export const xxxxupdate = (data) = > {
      return axios({
        method: 'post'.url: '/xxx/xx',
        data
      })
    }
    
    export const xxxx = (params) = > {
      return axios({
        method: 'get'.url: '/xxxx/xxxx',
        params
      })
    }
    Copy the code

Try to automate this with tools

Functional requirements

  1. The interface file can be automatically generated
  2. And mock
  3. And the group members can easily use it

Design idea:

Generate the corresponding interface file from a configuration file (such as fe.config.js) in the project root directory and mock it

  • The configuration file is as follows
// fe.config.js
module.exports = {
  // apiAndMock: This applies to the module of apiAndMock. Other tools have their keys
  apiAndMock: {
    config: { // The corresponding API file will be generated automatically based on the object here
      reportList: { // ReportList.js is generated (n keys are generated, n keys are generated)
        getReportList: {
          url: '/getReportList',},addReport: {
          url: '/addReport'.method: 'post' // Data is processed automatically
        },
        updateReport: {
          url: '/updateReport'.method: 'post' // Data is processed automatically
        },
        deleteReports: {
          url: '/deleteReports'.method: 'post' // Data is processed automatically
        }
      }
    }
  }
}
Copy the code

The difficulties in

  1. Difficulty 1: Users might wrap AXIos (or others), for example by adding request interception or response interception (such as doing some authentication).

    • At this point, the current project needs to use axiOS wrapped by the user.
    • Workaround: Add a configuration item myAxios as follows.You are advised to write an alias @ that represents the SRC directory
      • You also need to add myAxiosInstance, because some projects import instance directly and you can use it, but others require instance.instance
      module.exports = {
        apiAndMock: {
        + myAxios: "import instance from '@/axios/index.js'".// We recommend an alias @, representing the SRC directory,
        + myAxiosInstance: 'instance.instance'.config: { // The corresponding API file will be generated automatically based on the object here
            reportList: { // ReportList.js is generated (n keys are generated, n keys are generated). }}}}Copy the code

      What is wrapped Axios?

      • For example: here’s axios/index.js in my project, also wrapped axios

        // axios/index.js.// Create an axios instance
        const instance = axios.create({
          ...
        })
        
        // Add request interceptor
        instance.interceptors.request.use(function (config) {...return config
        }, function (error) {... })// Add a response interceptor
        instance.interceptors.response.use(function (response) {...return response
        }, function (error) {... })/ / initialization
        function install (Vue, opt) {
          // Add global methods
          Vue.prototype.$axios = instance
        }
        
        export default {
          install,
          instance
        }
        Copy the code
  2. Difficulty 2: It is also a requirement point, and I hope to complete the mock function together

    Add a data field, which will be used in mock mode, without affecting interface files

    module.exports = {
     // apiAndMock: This applies to the module of apiAndMock. Other tools have their keys
     apiAndMock: {
       myAxios: "import instance from '@/axios/index.js'".// We recommend an alias @, representing the SRC directory,
       myAxiosInstance: 'instance.instance'.config: { // The corresponding API file will be generated automatically based on the object here
         reportList: { // ReportList.js is generated (n keys are generated, n keys are generated)
           getReportList: {
             url: '/getReportList',
           + data: [ // The data here is used for mock generation
           +   {
           +     id: 1,
           +     reportName: '234',
           +     reportTitle: '33423',
           +     topicIds: '24 31',
           +     status: 0,
           +     startDate: '2020-11-01',
           +     lateDays: 5,
           +     createUser: 'xxx.li',
           +     updateUser: 'xx.li',
           +     createTime: 'the 2020-11-18 14:04:17',
           +     updateTime: 'the 2020-11-18 14:04:17'
           +   },
           +   {
           +     id: 2,
           +     reportName: '234',
           +     reportTitle: '33423',
           +     topicIds: '24 31',
           +     status: 0,
           +     startDate: '2020-11-01',
           +     lateDays: 5,
           +     createUser: 'xxx.li',
           +     updateUser: 'xx.li',
           +     createTime: 'the 2020-11-18 14:04:17',
           +     updateTime: 'the 2020-11-18 14:04:17'+} +]},addReport: {
             url: '/addReport'.method: 'post' // Data is processed automatically
           },
           updateReport: {
             url: '/updateReport'.method: 'post' // Data is processed automatically
           },
           deleteReports: {
             url: '/deleteReports'.method: 'post' // Data is processed automatically
           }
         }
       }
     }
    }
    Copy the code

    The specific implementation is explained below

  3. Difficulty 3: All the team members can use it easily

    Solution: We need to use our tool platform to build the internal front end tool platform

    NPM install -g@company /feTools

    The command must be executed in the root directory // 2. The fe.config.js configuration file must be prepared in advance. Mock // mock pattern fe API // MOCK pattern fe api-pkg // API pattern fe api-pkg // API pattern fe mock // mock pattern fe api-pkg // API pattern fe api-pkg // Compatible with some old projects)Copy the code

Difficulty 2: How to implement the Mock function

  1. First, how does the mock function work
  2. Consider automating the mock functionality

1. How is the mock function implemented first

Just introduce myMock/index.js anywhere to make your mock work

  • Use the axios-mock-adapter library, which intercepts the axios request and responds with the corresponding data if the path matches (see configuration below).
The mock folder directory structure is as follows: myMock Reportlist.js index.js Just introduce myMock/index.js anywhere to make your mock work// index.js 
var axios = require("axios")
// Use the mock library, which intercepts the axios request and responds with the corresponding data if the path matches (see configuration below).
var MockAdapter = require("axios-mock-adapter") 
var mock = new MockAdapter(axios)

import { init as reportList } from './reportList' // Introduce the mock response file
reportList(mock)


// reportList.js
export const init = (mock) = > {
  mock.onGet('/getReportList').reply(200, {
    data: [{"id":1."reportName":"xxx new"."reportTitle":"xxxx"."topicIds":"24 31"."status":0."startDate":"2020-11-01"."lateDays":5."createUser":"xxxx.li"."updateUser":"xxxx.li"."createTime":"The 2020-11-18 14:04:17"."updateTime":"The 2020-11-18 14:04:17"},
      {"id":2."reportName":"xxx new"."reportTitle":"xxxx"."topicIds":"24 31"."status":0."startDate":"2020-11-01"."lateDays":5."createUser":"xxxx.li"."updateUser":"xxxx.li"."createTime":"The 2020-11-18 14:04:17"."updateTime":"The 2020-11-18 14:04:17"}].ret: 0.msg: 'ok'
  })

  mock.onPost('/addReport').reply(200, {
    data: [].ret: 0.msg: 'ok'
  })

  mock.onPost('/updateReport').reply(200, {
    data: [].ret: 0.msg: 'ok'
  })

  mock.onPost('/deleteReports').reply(200, {
    data: [].ret: 0.msg: 'ok'})}Copy the code

2. Thinking about automating the mock feature

With the reference text above, it can be easily implemented in conjunction with the configuration file

Paste the final result according to the configuration file

Configuration file: fe.config.js

// fe.config.js
module.exports = {
  // apiAndMock: This applies to the module of apiAndMock. Other tools have their keys
  apiAndMock: {
    myAxios: "import instance from '@/axios/index.js'".// We recommend an alias @, representing the SRC directory,
    myAxiosInstance: 'instance.instance'.config: { // The corresponding API file will be generated automatically based on the object here
      reportList: { // ReportList.js is generated (n keys are generated, n keys are generated)
        getReportList: {
          url: '/getReportList'.data: [ // The data here is used for mock generation
            {
              id: 1.reportName: '234'.reportTitle: '33423'.topicIds: '24 31'.status: 0.startDate: '2020-11-01'.lateDays: 5.createUser: 'xxx.li'.updateUser: 'xx.li'.createTime: 'the 2020-11-18 14:04:17'.updateTime: 'the 2020-11-18 14:04:17'
            },
            {
              id: 2.reportName: '234'.reportTitle: '33423'.topicIds: '24 31'.status: 0.startDate: '2020-11-01'.lateDays: 5.createUser: 'xxx.li'.updateUser: 'xx.li'.createTime: 'the 2020-11-18 14:04:17'.updateTime: 'the 2020-11-18 14:04:17'}},addReport: {
          url: '/addReport'.method: 'post' // Data is processed automatically
        },
        updateReport: {
          url: '/updateReport'.method: 'post' // Data is processed automatically
        },
        deleteReports: {
          url: '/deleteReports'.method: 'post' // Data is processed automatically
        }
      }
    }
  }
}
Copy the code

Results obtained:

// Directory structure
api
    myApi
        myAxios.js // There are two cases of this file: mock mode and API mode
        reportList.js
    myMock
        index.js
        reportList.js
        
// myApi/ myaxios.js this file has two cases, one is mock mode, the other is API mode
// fe mock is a mock pattern that introduces mock files
/* This file is automatically generated and changes will not take effect */
import axiosRoot from 'axios' // Use the default axios
import '.. /myMock' // Mock files are introduced
export const axios = (obj) = > {
  return new Promise((resolve, reject) = > {
    axiosRoot(obj)
      .then(e= > {
        resolve(e && e.data)
      })
      .catch(err= > {
        console.error('Interface return error:' + JSON.stringify(err))
        reject(err)
      })
  })
}
console.log('Currently in mock mode')
// fe api-pkg is an API pattern that does not introduce mock files, but a user-wrapped axios instance
/* This file is automatically generated and changes will not take effect */
import instance from '@/axios/index.js'
export const axios = (obj) = > {
  return new Promise((resolve, reject) = > {
    instance.instance(obj)
      .then(e= > {
        resolve(e && e.data)
      })
      .catch(err= > {
        console.error('Interface return error:' + JSON.stringify(err))
        reject(err)
      })
  })
}


// myApi/reportList.js
/* This file is automatically generated, the modification will not take effect, the modification entry: fe.config.js */
import { axios } from './myAxios.js'

export const getReportList = (params) = > {
  return axios({
    method: 'get'.url: '/getReportList',
    params
  })
}

export const addReport = (data) = > {
  return axios({
    method: 'post'.url: '/addReport',
    data
  })
}

export const updateReport = (data) = > {
  return axios({
    method: 'post'.url: '/updateReport',
    data
  })
}

export const deleteReports = (data) = > {
  return axios({
    method: 'post'.url: '/deleteReports',
    data
  })
}


// myMock/index.js
/* This file is automatically generated, the modification will not take effect, the modification entry: fe.config.js */
var axios = require("axios")
var MockAdapter = require("axios-mock-adapter")
var mock = new MockAdapter(axios)

import { init as reportList } from './reportList'
reportList(mock)
    
    
// myMock/reportList.js
/* This file is automatically generated, the modification will not take effect, the modification entry: fe.config.js */
export const init = (mock) = > {
  mock.onGet('/getReportList').reply(200, {
    data: [{"id":1."reportName":"234"."reportTitle":"33423"."topicIds":"24 31"."status":0."startDate":"2020-11-01"."lateDays":5."createUser":"xxx.li"."updateUser":"xx.li"."createTime":"The 2020-11-18 14:04:17"."updateTime":"The 2020-11-18 14:04:17"},
      {"id":2."reportName":"234"."reportTitle":"33423"."topicIds":"24 31"."status":0."startDate":"2020-11-01"."lateDays":5."createUser":"xxx.li"."updateUser":"xx.li"."createTime":"The 2020-11-18 14:04:17"."updateTime":"The 2020-11-18 14:04:17"}].ret: 0.msg: 'ok'
  })

  mock.onPost('/addReport').reply(200, {
    data: [].ret: 0.msg: 'ok'
  })

  mock.onPost('/updateReport').reply(200, {
    data: [].ret: 0.msg: 'ok'
  })

  mock.onPost('/deleteReports').reply(200, {
    data: [].ret: 0.msg: 'ok'})}Copy the code

Code word is not easy, little praise to encourage ~