前端如何相对优雅管理api
一般来说,项目由子模块组成,拿到后端提供过来的接口,一般也是按照子模块来分类提供的.请教一下各位,你们前端项目是如何管理api的?
希望各位贴点你们的优秀代码段上来学习学习.
常见:
各个模块的api存放到单独的js文件里,返回一个请求实例promise对象
使用的时候根据需求引入相应的请求方法
// axios/request.js 文件:
/* 创建axios请求实例,并返回实例 代码就不贴上来了*/
// axios/apis/home.js 文件: import request from "../request"; //获取菜单 export function getHomeNav(params) { return request({ url: "/api/home/getNav", params: params }); } //获取热门新闻 export function getHotNewsList(params) { return request({ url: "/api/home/getHotNewsList", params: params }); }
// axios/apis/my.js 文件: // 获取用户信息 export function getUserInfo(params) { return request({ url: "/api/get/user/info", params: params }); } // 更新用户信息 export function updateUserInfo(params) { return request({ url: "/api/post/user/update", data: params }); }
// 使用文件: import { getHomeNav, getHotNewsList } from '@/axios/apis/home.js'
import { getUserInfo, updateUserInfo} from '@/axios/apis/home.js'
getHomeNav({}).then(res=>{ console.log(res) });
个人在某个项目上,烦透了在使用的时候一个个api请求方法引入.花了点时间,改成了所有api直接挂在一个全局变量上.牺牲了点性能,但是使用起来爽歪歪的感觉.
假如axios/apis/home.js文件: export default { //获取菜单 nav: { url: "/api/home/getNav", method: "get", config:{timeout:50000} // 会覆盖到axios实例的config对应的属性 }, body: { //getHotNewsList getHotNewsList: { url: "/api/home/getHotNewsList", method: "get", }, //getList getList: { url: "/api/home/getList", method: "get", }, }, };
全局引入所有API:
import requireApi from '@/axios/index.js'
const APIS = requireApi();
home里的api调用可以这样:
APIS.home.nav({page:1,sizePages:20}).then(res=>{ ... })
APIS.home.body.getHotNewsList({page:1,sizePages:20}).then(res=>{ ... })
假如另外有一个my的模块api,使用起来可以这样:
APIS.my.xxxx().then(res=>{ ... });
下面是实现代码段:
// 假如目前有两个模块的api,分别存放在home.js,my.js里
// axios/apis/home.js文件:
export default { //获取菜单 nav: { url: "/api/home/getNav", method: "get", config:{timeout:50000} // 会覆盖到axios实例的config对应的属性 }, body: { //getHotNewsList getHotNewsList: { url: "/api/home/getHotNewsList", method: "get", }, //getList getList: { url: "/api/home/getList", method: "get", }, }, };
// axion/apis/my.js文件:
export default { // 获取用户信息 getUserInfo: { url: "/api/get/user/info", method: "get", }, // 更新用户信息 updateUserInfo: { url: "/api/post/user/update", method: "post", }, };
// axios/index.js 文件: import createApiFn from "./createApiFn"; /** * 把api文件夹下的所有Api文件require进来,在逐个export出去 * 假如axios/apis/home.js文件: export default { //获取菜单 nav: { url: "/api/home/getNav", method: "get", config:{timeout:50000} // 会覆盖到axios实例的config对应的属性 }, body: { //getHotNewsList getHotNewsList: { url: "/api/home/getHotNewsList", method: "get", }, //getList getList: { url: "/api/home/getList", method: "get", }, }, }; * 按需求引入: * import { home } from '@/axios/index.js' * home.nav({page:1,sizePages:20}).then(res=>{ ... }) * home.body.getHotNewsList({page:1,sizePages:20}).then(res=>{ ... }) * * 全局引入所有API: * import requireApi from '@/axios/index.js' * const APIS = requireApi(); * APIS.home.nav({page:1,sizePages:20}).then(res=>{ ... }) * APIS.home.body.getHotNewsList({page:1,sizePages:20}).then(res=>{ ... }) */ /** // webpack let requireApi = () => { let allApi = require.context("./apis/", false, /\.js$/), allApiFnObj = {}; allApi.keys().map((item) => { allApiFnObj[item.replace(/(\.\/|\.js)/g, "")] = createApiFn(allApi(item).default); }); return allApiFnObj; }; */ // vite let requireApi = () => { let allApi = import.meta.globEager('./apis/*.js'), allApiFnObj = {}; Object.keys(allApi).map((item) => { const fileName = item.replace(/\.\/apis\/|\.js/g, ''); allApiFnObj[fileName] = createApiFn(allApi[item].default); }); return allApiFnObj; }; export default requireApi; // 需要手动把各个模块export出去 let { home, my } = requireApi(); export { home, my };
// axios/createApiFn.js文件: import requestInstance from "./request"; const bindPromiseFn = (apiObj, args, config={}) => { const params = { method: apiObj.method || "get", url: apiObj.url, params: args, config: apiObj.config || {}, }; params.config = { ...params.config, ...config } return requestInstance(params); }; /** * 把apis对象转变成以字段名为方法名的对象 * 如: * apis={ * getDemo:{ * url:"xxxx", * method: "get" * }, * postDemo:{} * } * 执行方法后返回对象结构如下: * { * getDemo:function(){}, * postDemo:function(){} * } * @param {object} apis */ const createApiFn = (apis) => { var obj = {}; Object.keys(apis).map((key) => { if (apis[key] && apis[key].url) { obj[key] = (function (apiObj) { /** * args 请求入参 * config 请求配置相关信息,最终会传给实例axios.config */ return function (args,config={}) { return bindPromiseFn(apiObj, args, config); }; })(apis[key]); } else if ( apis[key] && !apis[key].url && Object.prototype.toString.call(apis[key]) === "[object Object]") { obj[key] = createApiFn(apis[key]); } }); return obj; }; export default createApiFn;
// axios/request.js 文件: import axios from "axios"; // 创建axios实例 const axiosInstance = (config = {}) => { const _config = { // baseURL: `${location.protocol}//${process.env.VUE_APP_BASE_API}`, // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。 timeout: 30000, }; config = { ..._config, ...config }; return axios.create(config); }; const requestInstance = (args) => { let { method, url, params, config = {} } = args; if (!url) { return; } if (method === "get") { params = { params: params }; } const instance = axiosInstance(config); instance.interceptors.request.use( (config) => { // config.headers["x-auth-token"] = getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改 return config; }, (error) => { return Promise.reject(error); } ); instance.interceptors.response.use( (response) => { const { status, statusText, data } = response if (status === 200 || status === 304) { return Promise.resolve(data); } else { return Promise.reject(statusText || "Error"); } }, (error) => { return Promise.reject(error); } ); debugger; return instance[method](url, params, config); }; export default requestInstance;
//全局引入所有API使用方法: import requireApi from '../axios/index' const API = requireApi(); API.my.updateUserInfo({name:'xiaomou'}).then(res=>{ console.log(res); }) APIS.home.body.getHotNewsList({page:1,sizePages:20}).then(res=>{ ... }) //按需求引入方法: import { home } from '@/axios/index.js' home.body.getHotNewsList({page:1,sizePages:20}).then(res=>{ ... })