开发一个自动生成接口文件且带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.js
module.exports = {
// apiAndMock:此处适用于apiAndMock的模块,其他工具有其的key
apiAndMock: {
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的模块,其他工具有其的key
apiAndMock: {
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文件夹的目录结构如下:
myMock
reportList.js
index.js
只需在任意地方引入 myMock/index.js 就能让mock生效了
// index.js
var 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.js
export 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.js
module.exports = {
// apiAndMock:此处适用于apiAndMock的模块,其他工具有其的key
apiAndMock: {
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请求
}
}
}
}
}
得到的结果:
// 目录结构
api
myApi
myAxios.js // 这个文件有2种情况,一种是mock模式,一种是api模式
reportList.js
myMock
index.js
reportList.js
// myApi/myAxios.js 这个文件有2种情况,一种是mock模式,一种是api模式
// fe mock 是mock模式, 引入了mock文件
/* 此文件是自动生成的, 在此修改会不生效 */
import axiosRoot from 'axios' // 用默认的axios
import '../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'
})
}
码字不易,点点小赞鼓励~