开发一个自动生成接口文件且带mock功能的工具
痛点是:
- 写接口的api文件(如下),比较麻烦。大多数接口,都是同一种格式,要么get要么post。每次都是重复性的写。
- 根据DRY(don’t repeat yourself)原则,我们尝试把这个自动化
// 这是 api文件, 每次都要重复性的写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})}
尝试用工具把这个自动化实现了
功能要求
- 能自动生成对应的接口文件
- 并带mock功能
- 且小组成员都可以很容易的使用
设计思路:
在项目根目录下 根据一个配置文件(比如:fe.config.js) 去生成对应的接口文件,并带mock功能
- 配置文件如下
// fe.config.jsmodule.exports = {// apiAndMock:此处适用于apiAndMock的模块,其他工具有其的keyapiAndMock: {config: { // 会根据此处的对象,自动生成对应的api文件reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )getReportList: {url: '/getReportList',},addReport: {url: '/addReport',method: 'post' // 自动处理成data, 不写的话, 默认get请求},updateReport: {url: '/updateReport',method: 'post' // 自动处理成data, 不写的话, 默认get请求},deleteReports: {url: '/deleteReports',method: 'post' // 自动处理成data, 不写的话, 默认get请求}}}}}
难点
- 难点1:用户可能会对axios(或其他)做一层包装,比如增加 请求拦截 或 响应拦截(比如做一些鉴权)。
- 此时当前的项目,就需要用到用户封装过的axios。
- 解决办法:增加一个配置项 myAxios,如下。建议写别名@,代表src目录
- 还需增加 myAxiosInstance,因为有些项目直接import导入 instance 就能使用,但有些项目需要instance.instance 才能使用
module.exports = {apiAndMock: {+ myAxios: "import instance from '@/axios/index.js'", // 建议写别名@,代表src目录,+ myAxiosInstance: 'instance.instance',config: { // 会根据此处的对象,自动生成对应的api文件reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )...}}}}
什么是封装过的axios?
- 举个例子:这是我的项目内的axios/index.js,也是封装过的axios
// axios/index.js...// 创建axios实例const instance = axios.create({...})// 添加请求拦截器instance.interceptors.request.use(function (config) {...return config}, function (error) {...})// 添加响应拦截器instance.interceptors.response.use(function (response) {...return response}, function (error) {...})// 初始化function install (Vue, opt) {// 添加全局方法Vue.prototype.$axios = instance}export default {install,instance}
难点2:也算是需求点,希望能一并完成mock功能
设计思路,增加一个data字段,mock模式下会用到,不影响接口文件
具体的实现,下面有详解module.exports = {// apiAndMock:此处适用于apiAndMock的模块,其他工具有其的keyapiAndMock: {myAxios: "import instance from '@/axios/index.js'", // 建议写别名@,代表src目录,myAxiosInstance: 'instance.instance',config: { // 会根据此处的对象,自动生成对应的api文件reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )getReportList: {url: '/getReportList',+ data: [ // 生成mock时, 才会用到此处的data+ {+ 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'+ },+ {+ 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'+ }+ ]},addReport: {url: '/addReport',method: 'post' // 自动处理成data, 不写的话, 默认get请求},updateReport: {url: '/updateReport',method: 'post' // 自动处理成data, 不写的话, 默认get请求},deleteReports: {url: '/deleteReports',method: 'post' // 自动处理成data, 不写的话, 默认get请求}}}}}
难点3:小组成员都可以很容易的使用
解决方法:又需要用到我们的工具平台了内部前端工具平台搭建
npm install -g @company/feTools 后// 注意 1. 命令需在根目录下执行// 2. 需提前配好配置文件 fe.config.js// 3. 输出的文件会在:`src/api` 内fe mock // mock模式fe api // api模式(标准模式)fe api-pkg // api模式(处理一下响应结果,只返回响应数据的data,不反回header等等。兼容一些老项目)
难点2详解:如何实现mock功能
- 首先看看mock功能如何实现
- 在考虑把mock功能自动化
1. 首先看看mock功能如何实现
只需在任意地方引入 myMock/index.js 就能让mock生效了
- 使用axios-mock-adapter库,这库的原理是:会拦截axios的请求,如果匹配到了对应的path,会响应出对应的data(下方有配置)
mock文件夹的目录结构如下:myMockreportList.jsindex.js只需在任意地方引入 myMock/index.js 就能让mock生效了// index.jsvar axios = require("axios")// 使用mock库,这库的原理是:会拦截axios的请求,如果匹配到了对应的path,会响应出对应的data(下方有配置)var MockAdapter = require("axios-mock-adapter")var mock = new MockAdapter(axios)import { init as reportList } from './reportList' // 引入mock响应文件reportList(mock)// reportList.jsexport const init = (mock) => {mock.onGet('/getReportList').reply(200, {data: [{"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"},{"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"}],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'})}
2. 在考虑把mock功能自动化
有了上面的参考文本后,在结合 配置文件,可以很轻松的实现
根据配置文件,贴上最终得到的结果
配置文件: fe.config.js
// fe.config.jsmodule.exports = {// apiAndMock:此处适用于apiAndMock的模块,其他工具有其的keyapiAndMock: {myAxios: "import instance from '@/axios/index.js'", // 建议写别名@,代表src目录,myAxiosInstance: 'instance.instance',config: { // 会根据此处的对象,自动生成对应的api文件reportList: { // 会生成reportList.js ( 有n个key, 则生成n个[key].js )getReportList: {url: '/getReportList',data: [ // 生成mock时, 才会用到此处的data{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'},{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'}]},addReport: {url: '/addReport',method: 'post' // 自动处理成data, 不写的话, 默认get请求},updateReport: {url: '/updateReport',method: 'post' // 自动处理成data, 不写的话, 默认get请求},deleteReports: {url: '/deleteReports',method: 'post' // 自动处理成data, 不写的话, 默认get请求}}}}}
得到的结果:
// 目录结构apimyApimyAxios.js // 这个文件有2种情况,一种是mock模式,一种是api模式reportList.jsmyMockindex.jsreportList.js// myApi/myAxios.js 这个文件有2种情况,一种是mock模式,一种是api模式// fe mock 是mock模式, 引入了mock文件/* 此文件是自动生成的, 在此修改会不生效 */import axiosRoot from 'axios' // 用默认的axiosimport '../myMock' // 引入了mock文件export const axios = (obj) => {return new Promise((resolve, reject) => {axiosRoot(obj).then(e => {resolve(e && e.data)}).catch(err => {console.error('接口返回错误: ' + JSON.stringify(err))reject(err)})})}console.log('当前是mock模式')// fe api-pkg 是api模式, 没有引入了mock文件,引入了用户封装过的axios实例/* 此文件是自动生成的, 在此修改会不生效 */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('接口返回错误: ' + JSON.stringify(err))reject(err)})})}// myApi/reportList.js/* 此文件是自动生成的, 在此修改会不生效, 修改入口: 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/* 此文件是自动生成的, 在此修改会不生效, 修改入口: 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/* 此文件是自动生成的, 在此修改会不生效, 修改入口: fe.config.js */export const init = (mock) => {mock.onGet('/getReportList').reply(200, {data: [{"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"},{"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"}],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'})}
码字不易,点点小赞鼓励~
