开发一个自动生成接口文件且带mock功能的工具

痛点是:

  1. 写接口的api文件(如下),比较麻烦。大多数接口,都是同一种格式,要么get要么post。每次都是重复性的写。
    • 根据DRY(don’t repeat yourself)原则,我们尝试把这个自动化
  1. // 这是 api文件, 每次都要重复性的写
  2. import { axios } from './myAxios.js'
  3. export const xxxxList = (data) => {
  4. return axios({
  5. method: 'post',
  6. url: '/xxx/xxx',
  7. data
  8. })
  9. }
  10. export const xxxxupdate = (data) => {
  11. return axios({
  12. method: 'post',
  13. url: '/xxx/xx',
  14. data
  15. })
  16. }
  17. export const xxxx = (params) => {
  18. return axios({
  19. method: 'get',
  20. url: '/xxxx/xxxx',
  21. params
  22. })
  23. }


尝试用工具把这个自动化实现了

功能要求

  1. 能自动生成对应的接口文件
  2. 并带mock功能
  3. 且小组成员都可以很容易的使用

设计思路:

在项目根目录下 根据一个配置文件(比如:fe.config.js) 去生成对应的接口文件,并带mock功能

  • 配置文件如下
  1. // fe.config.js
  2. module.exports = {
  3. // apiAndMock:此处适用于apiAndMock的模块,其他工具有其的key
  4. apiAndMock: {
  5. config: { // 会根据此处的对象,自动生成对应的api文件
  6. reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )
  7. getReportList: {
  8. url: '/getReportList',
  9. },
  10. addReport: {
  11. url: '/addReport',
  12. method: 'post' // 自动处理成data, 不写的话, 默认get请求
  13. },
  14. updateReport: {
  15. url: '/updateReport',
  16. method: 'post' // 自动处理成data, 不写的话, 默认get请求
  17. },
  18. deleteReports: {
  19. url: '/deleteReports',
  20. method: 'post' // 自动处理成data, 不写的话, 默认get请求
  21. }
  22. }
  23. }
  24. }
  25. }

难点

  1. 难点1:用户可能会对axios(或其他)做一层包装,比如增加 请求拦截 或 响应拦截(比如做一些鉴权)。
    • 此时当前的项目,就需要用到用户封装过的axios。
    • 解决办法:增加一个配置项 myAxios,如下。建议写别名@,代表src目录
      • 还需增加 myAxiosInstance,因为有些项目直接import导入 instance 就能使用,但有些项目需要instance.instance 才能使用
  1. module.exports = {
  2. apiAndMock: {
  3. + myAxios: "import instance from '@/axios/index.js'", // 建议写别名@,代表src目录,
  4. + myAxiosInstance: 'instance.instance',
  5. config: { // 会根据此处的对象,自动生成对应的api文件
  6. reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )
  7. ...
  8. }
  9. }
  10. }
  11. }

什么是封装过的axios?

  1. - 举个例子:这是我的项目内的axios/index.js,也是封装过的axios
  1. // axios/index.js
  2. ...
  3. // 创建axios实例
  4. const instance = axios.create({
  5. ...
  6. })
  7. // 添加请求拦截器
  8. instance.interceptors.request.use(function (config) {
  9. ...
  10. return config
  11. }, function (error) {
  12. ...
  13. })
  14. // 添加响应拦截器
  15. instance.interceptors.response.use(function (response) {
  16. ...
  17. return response
  18. }, function (error) {
  19. ...
  20. })
  21. // 初始化
  22. function install (Vue, opt) {
  23. // 添加全局方法
  24. Vue.prototype.$axios = instance
  25. }
  26. export default {
  27. install,
  28. instance
  29. }
  1. 难点2:也算是需求点,希望能一并完成mock功能
    设计思路,增加一个data字段,mock模式下会用到,不影响接口文件
    具体的实现,下面有详解

    1. module.exports = {
    2. // apiAndMock:此处适用于apiAndMock的模块,其他工具有其的key
    3. apiAndMock: {
    4. myAxios: "import instance from '@/axios/index.js'", // 建议写别名@,代表src目录,
    5. myAxiosInstance: 'instance.instance',
    6. config: { // 会根据此处的对象,自动生成对应的api文件
    7. reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )
    8. getReportList: {
    9. url: '/getReportList',
    10. + data: [ // 生成mock时, 才会用到此处的data
    11. + {
    12. + id: 1,
    13. + reportName: '234',
    14. + reportTitle: '33423',
    15. + topicIds: '24,3,2',
    16. + status: 0,
    17. + startDate: '2020-11-01',
    18. + lateDays: 5,
    19. + createUser: 'xxx.li',
    20. + updateUser: 'xx.li',
    21. + createTime: '2020-11-18 14:04:17',
    22. + updateTime: '2020-11-18 14:04:17'
    23. + },
    24. + {
    25. + id: 2,
    26. + reportName: '234',
    27. + reportTitle: '33423',
    28. + topicIds: '24,3,2',
    29. + status: 0,
    30. + startDate: '2020-11-01',
    31. + lateDays: 5,
    32. + createUser: 'xxx.li',
    33. + updateUser: 'xx.li',
    34. + createTime: '2020-11-18 14:04:17',
    35. + updateTime: '2020-11-18 14:04:17'
    36. + }
    37. + ]
    38. },
    39. addReport: {
    40. url: '/addReport',
    41. method: 'post' // 自动处理成data, 不写的话, 默认get请求
    42. },
    43. updateReport: {
    44. url: '/updateReport',
    45. method: 'post' // 自动处理成data, 不写的话, 默认get请求
    46. },
    47. deleteReports: {
    48. url: '/deleteReports',
    49. method: 'post' // 自动处理成data, 不写的话, 默认get请求
    50. }
    51. }
    52. }
    53. }
    54. }
  2. 难点3:小组成员都可以很容易的使用
    解决方法:又需要用到我们的工具平台了内部前端工具平台搭建
    npm install -g @company/feTools 后

    1. // 注意 1. 命令需在根目录下执行
    2. // 2. 需提前配好配置文件 fe.config.js
    3. // 3. 输出的文件会在:`src/api` 内
    4. fe mock // mock模式
    5. fe api // api模式(标准模式)
    6. fe api-pkg // api模式(处理一下响应结果,只返回响应数据的data,不反回header等等。兼容一些老项目)

难点2详解:如何实现mock功能

  1. 首先看看mock功能如何实现
  2. 在考虑把mock功能自动化

1. 首先看看mock功能如何实现

只需在任意地方引入 myMock/index.js 就能让mock生效了

  • 使用axios-mock-adapter库,这库的原理是:会拦截axios的请求,如果匹配到了对应的path,会响应出对应的data(下方有配置)
  1. mock文件夹的目录结构如下:
  2. myMock
  3. reportList.js
  4. index.js
  5. 只需在任意地方引入 myMock/index.js 就能让mock生效了
  6. // index.js
  7. var axios = require("axios")
  8. // 使用mock库,这库的原理是:会拦截axios的请求,如果匹配到了对应的path,会响应出对应的data(下方有配置)
  9. var MockAdapter = require("axios-mock-adapter")
  10. var mock = new MockAdapter(axios)
  11. import { init as reportList } from './reportList' // 引入mock响应文件
  12. reportList(mock)
  13. // reportList.js
  14. export const init = (mock) => {
  15. mock.onGet('/getReportList').reply(200, {
  16. data: [
  17. {"id":1,"reportName":"xxx new","reportTitle":"xxxx","topicIds":"24,3,2","status":0,"startDate":"2020-11-01","lateDays":5,"createUser":"xxxx.li","updateUser":"xxxx.li","createTime":"2020-11-18 14:04:17","updateTime":"2020-11-18 14:04:17"},
  18. {"id":2,"reportName":"xxx new","reportTitle":"xxxx","topicIds":"24,3,2","status":0,"startDate":"2020-11-01","lateDays":5,"createUser":"xxxx.li","updateUser":"xxxx.li","createTime":"2020-11-18 14:04:17","updateTime":"2020-11-18 14:04:17"}
  19. ],
  20. ret: 0,
  21. msg: 'ok'
  22. })
  23. mock.onPost('/addReport').reply(200, {
  24. data: [],
  25. ret: 0,
  26. msg: 'ok'
  27. })
  28. mock.onPost('/updateReport').reply(200, {
  29. data: [],
  30. ret: 0,
  31. msg: 'ok'
  32. })
  33. mock.onPost('/deleteReports').reply(200, {
  34. data: [],
  35. ret: 0,
  36. msg: 'ok'
  37. })
  38. }

2. 在考虑把mock功能自动化

有了上面的参考文本后,在结合 配置文件,可以很轻松的实现

根据配置文件,贴上最终得到的结果

配置文件: fe.config.js

  1. // fe.config.js
  2. module.exports = {
  3. // apiAndMock:此处适用于apiAndMock的模块,其他工具有其的key
  4. apiAndMock: {
  5. myAxios: "import instance from '@/axios/index.js'", // 建议写别名@,代表src目录,
  6. myAxiosInstance: 'instance.instance',
  7. config: { // 会根据此处的对象,自动生成对应的api文件
  8. reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )
  9. getReportList: {
  10. url: '/getReportList',
  11. data: [ // 生成mock时, 才会用到此处的data
  12. {
  13. id: 1,
  14. reportName: '234',
  15. reportTitle: '33423',
  16. topicIds: '24,3,2',
  17. status: 0,
  18. startDate: '2020-11-01',
  19. lateDays: 5,
  20. createUser: 'xxx.li',
  21. updateUser: 'xx.li',
  22. createTime: '2020-11-18 14:04:17',
  23. updateTime: '2020-11-18 14:04:17'
  24. },
  25. {
  26. id: 2,
  27. reportName: '234',
  28. reportTitle: '33423',
  29. topicIds: '24,3,2',
  30. status: 0,
  31. startDate: '2020-11-01',
  32. lateDays: 5,
  33. createUser: 'xxx.li',
  34. updateUser: 'xx.li',
  35. createTime: '2020-11-18 14:04:17',
  36. updateTime: '2020-11-18 14:04:17'
  37. }
  38. ]
  39. },
  40. addReport: {
  41. url: '/addReport',
  42. method: 'post' // 自动处理成data, 不写的话, 默认get请求
  43. },
  44. updateReport: {
  45. url: '/updateReport',
  46. method: 'post' // 自动处理成data, 不写的话, 默认get请求
  47. },
  48. deleteReports: {
  49. url: '/deleteReports',
  50. method: 'post' // 自动处理成data, 不写的话, 默认get请求
  51. }
  52. }
  53. }
  54. }
  55. }

得到的结果:

  1. // 目录结构
  2. api
  3. myApi
  4. myAxios.js // 这个文件有2种情况,一种是mock模式,一种是api模式
  5. reportList.js
  6. myMock
  7. index.js
  8. reportList.js
  9. // myApi/myAxios.js 这个文件有2种情况,一种是mock模式,一种是api模式
  10. // fe mock 是mock模式, 引入了mock文件
  11. /* 此文件是自动生成的, 在此修改会不生效 */
  12. import axiosRoot from 'axios' // 用默认的axios
  13. import '../myMock' // 引入了mock文件
  14. export const axios = (obj) => {
  15. return new Promise((resolve, reject) => {
  16. axiosRoot(obj)
  17. .then(e => {
  18. resolve(e && e.data)
  19. })
  20. .catch(err => {
  21. console.error('接口返回错误: ' + JSON.stringify(err))
  22. reject(err)
  23. })
  24. })
  25. }
  26. console.log('当前是mock模式')
  27. // fe api-pkg 是api模式, 没有引入了mock文件,引入了用户封装过的axios实例
  28. /* 此文件是自动生成的, 在此修改会不生效 */
  29. import instance from '@/axios/index.js'
  30. export const axios = (obj) => {
  31. return new Promise((resolve, reject) => {
  32. instance.instance(obj)
  33. .then(e => {
  34. resolve(e && e.data)
  35. })
  36. .catch(err => {
  37. console.error('接口返回错误: ' + JSON.stringify(err))
  38. reject(err)
  39. })
  40. })
  41. }
  42. // myApi/reportList.js
  43. /* 此文件是自动生成的, 在此修改会不生效, 修改入口: fe.config.js */
  44. import { axios } from './myAxios.js'
  45. export const getReportList = (params) => {
  46. return axios({
  47. method: 'get',
  48. url: '/getReportList',
  49. params
  50. })
  51. }
  52. export const addReport = (data) => {
  53. return axios({
  54. method: 'post',
  55. url: '/addReport',
  56. data
  57. })
  58. }
  59. export const updateReport = (data) => {
  60. return axios({
  61. method: 'post',
  62. url: '/updateReport',
  63. data
  64. })
  65. }
  66. export const deleteReports = (data) => {
  67. return axios({
  68. method: 'post',
  69. url: '/deleteReports',
  70. data
  71. })
  72. }
  73. // myMock/index.js
  74. /* 此文件是自动生成的, 在此修改会不生效, 修改入口: fe.config.js */
  75. var axios = require("axios")
  76. var MockAdapter = require("axios-mock-adapter")
  77. var mock = new MockAdapter(axios)
  78. import { init as reportList } from './reportList'
  79. reportList(mock)
  80. // myMock/reportList.js
  81. /* 此文件是自动生成的, 在此修改会不生效, 修改入口: fe.config.js */
  82. export const init = (mock) => {
  83. mock.onGet('/getReportList').reply(200, {
  84. data: [
  85. {"id":1,"reportName":"234","reportTitle":"33423","topicIds":"24,3,2","status":0,"startDate":"2020-11-01","lateDays":5,"createUser":"xxx.li","updateUser":"xx.li","createTime":"2020-11-18 14:04:17","updateTime":"2020-11-18 14:04:17"},
  86. {"id":2,"reportName":"234","reportTitle":"33423","topicIds":"24,3,2","status":0,"startDate":"2020-11-01","lateDays":5,"createUser":"xxx.li","updateUser":"xx.li","createTime":"2020-11-18 14:04:17","updateTime":"2020-11-18 14:04:17"}
  87. ],
  88. ret: 0,
  89. msg: 'ok'
  90. })
  91. mock.onPost('/addReport').reply(200, {
  92. data: [],
  93. ret: 0,
  94. msg: 'ok'
  95. })
  96. mock.onPost('/updateReport').reply(200, {
  97. data: [],
  98. ret: 0,
  99. msg: 'ok'
  100. })
  101. mock.onPost('/deleteReports').reply(200, {
  102. data: [],
  103. ret: 0,
  104. msg: 'ok'
  105. })
  106. }

码字不易,点点小赞鼓励~