统一加载整个目录中的 API
背景:接手的项目已经有一个 api 目录以使用方式如下表示。
src/api:.
│ logs.js
│
├─aiplatform
│ application.js
│ label.js
├─assist
│ assist.js
│
├─base
│ region.js
│
├─classify
│ ├─dialogue
│ │ chat.js
│ │ data.js
│ │
│ ├─label
│ │ index.js
│ │
│ └─mould
│ list.js
│ test.js
│
├─common
│ common.js
│
├─desk
│ notice.js
其中的 js 文件内容示例:
import request from '@/router/axios';
export const getList = (current, size, params) => {
return request({
url: '/api/blade-desk/notice/list',
method: 'get',
params: {
...params,
current,
size,
}
})
}
export const remove = (ids) => {
return request({
url: '/api/blade-desk/notice/remove',
method: 'post',
params: {
ids,
}
})
}
所有接口引用方式示例:
import { getList } from "@/api/aiplatform/application";
getList(cnt).then( res => {
console.log(res.data.data)
})
个人感觉之种方式不太间接,想逐步修改它们。
- 目录层级划分太多,管理起来十分繁琐
- 接口声明没有把 method 和 url 以及参数进行封装,声明一个接口得首先一陀代码
- 每个使用时都必须
import { xxxx } "..."
- 接口响应中的主要数据部分没有经过统一处理,每个使用的地方都得 res.data.data...
修改后的调用方式
- 直接引用,无需导入
- 直接返回响应中的主要数据
this.$api.aiplatform.application.getList(cnt).then( res => {
console.log(res) //
})
实现方式
在 api 目录下创建 index.js 文件,内容为:
import lodash from 'lodash'
const files = require.context('./', true, /.js$/);
const apiMaps = {}
files.keys().forEach(key => {
const path = key.replace(/^./|.js$/g, ``).replace(///g, `.`)
const obj = files(key) // 如果文件内容写了 export default, 那么这里是 files(key).default
const objRes = {}
Object.keys(obj).forEach(key => { // 对每个 API 统一添加拦截器, 本来这个功能应该在 axios 的, 为了不影响已有的代码,另开了一个功能
let fn = obj[key]
objRes[key] = (...arg) => {
return new Promise((resove, reject) => {
fn(...arg).then(res => {
const inRes = (res) => { // 响应拦截器
if(res.status === 200) {
return res.data.data
} else {
throw new Error(res.msg)
}
}
resove(inRes(res))
}).catch(err => {
reject(err)
})
})
}
})
lodash.set(apiMaps, path, objRes)
})
export default apiMaps
在入口 main.js 中添加以下内容:
import api from '@/api'
Vue.prototype.$api = api
然后就能在使用的地方通过 this.$api.目录.方法
的形式调用接口了,不影响原来的调用方式。
核心知识点
- webpack 中的 require.context