useAxios 的包装函数
useAxiosWrapper,该函数旨在于实现 useAxios 的封装。
安装依赖
bash
pnpm i -P @vueuse/integrations axios
准备接口返回数据的类型
接口请求返回类型,通常是一个泛型,请根据你的业务场景准备好类似于下面的类型:
详情
ts
/**
* apifox 生成的标准返回值对象
* @description
* 接口请求的标准返回值对象 接口的返回值均满足该对象
*/
export interface ApifoxModel<T> {
/**
* 业务状态码, 1成功, 其他失败
*/
code: string;
/**
* 响应消息
*/
msg: string;
/**
* 响应结果
*/
result: T;
}
准备简单的 axios 请求实例
这里的本质是为了准备一个拦截器内没有解包 data 的 axios 实例,因为 useAxios 默认帮我们完成 axios 的 data 解包了。
比如以下的简单实例:
详情
ts
import axios from "axios";
import qs from "qs";
/**
* 创建axios实例
* @description
* 从商城项目内获取得来
*
* @see https://apifox.com/apidoc/shared-c05cb8d7-e591-4d9c-aff8-11065a0ec1de/api-67132167
*/
export function createAxiosInstance() {
const instance = axios.create({
baseURL: "https://pcapi-xiaotuxian-front-devtest.itheima.net",
/** 请求超时时间 */
timeout: 10000,
/** 允许跨域 */
withCredentials: true,
/**
* 在 vitest 内做接口请求时,会使用node环境内的环境变量
* 比如 HTTPS_PROXY 变量。这里设置为false,不使用代理。
*/
proxy: false,
});
// 使用qs序列化参数params参数
instance.defaults.paramsSerializer = function (params) {
return qs.stringify(params);
};
return instance;
}
基于项目二次封装 useAxiosWrapper 函数
详情
ts
import type { PartialPick } from "type-plus";
import { useAxiosWrapper } from "@ruan-cat/utils/vueuse";
import type { UseAxiosOptionsBase, UseAxiosWrapperParams, KeyAxiosRequestConfig } from "@ruan-cat/utils/vueuse";
import type { ApifoxModel } from "./types/ApifoxModel";
import { createAxiosInstance } from "./createAxiosInstance";
/**
* 提供默认返回值的包装类型
* @description
* 预期会在每一个接口的包装函数内使用 用来定义 useAxios 的options参数
*
* 该类型应该成为高频使用的工具类型
*
* 被设计成一个简单的类型 而不是interface接口
*
* 推荐在你的业务内自己二次封装这样的返回值类型
*/
export type UseAxiosOptionsWithReturnWrapper<T = any> = UseAxiosOptionsBase<ApifoxModel<T>>;
/**
* 根据你的业务 二次包装接口请求的传递参数
* 这里最重要的是使用 ApifoxModel 来约束你的接口返回数据
* 否则你每次定义接口请求函数时,都要写一次 ApifoxModel 来约束返回值结构,很繁琐。
*/
interface _Params<K extends KeyAxiosRequestConfig, T = any, D = any>
extends UseAxiosWrapperParams<K, T, UseAxiosOptionsBase<ApifoxModel<T>>, D> {}
/**
* 建议封装接口请求函数不传递 useAxios 的 instance 和 options 参数。
*/
type Params<K extends KeyAxiosRequestConfig, T = any, D = any> = PartialPick<_Params<K, T, D>, "instance" | "options">;
/**
* 接口请求时用的请求实例
*/
const projectRequestInstance = createAxiosInstance();
/** @private 我们推荐你新建一个内部类型 移除掉多余key值 避免使用函数做请求时 反复声明无意义的变量 */
type RemoveMethod<T extends KeyAxiosRequestConfig> = Exclude<T, "method">;
/**
* 项目内用的接口请求
* @description
* 推荐将 options 和 instance 参数提前封装好,不要每次调用接口请求函数时传递
*/
export function projectRequest<K extends KeyAxiosRequestConfig, T = any, D = any>(
params: Params<RemoveMethod<K>, T, D>,
) {
const {
url,
config,
options = {
immediate: false,
},
instance = projectRequestInstance,
} = params;
return useAxiosWrapper<RemoveMethod<K>, ApifoxModel<T>, UseAxiosOptionsBase<ApifoxModel<T>>, D>({
config,
instance,
options,
url,
});
}
定义接口
如下:
详情
ts
import { projectRequest, type UseAxiosOptionsWithReturnWrapper } from "./projectRequest";
import { HomeCategoryHeads, HomeCategoryHeadsParams } from "./types/business";
/**
* 具体的业务接口
* @see https://apifox.com/apidoc/shared-c05cb8d7-e591-4d9c-aff8-11065a0ec1de/api-67132163
*/
export function homeCategoryHead<T = HomeCategoryHeads[]>(options?: UseAxiosOptionsWithReturnWrapper<T>) {
/**
* 定义接口的dto返回值
* 接口传参时使用的字段
* 传参时传递的vo对象
*/
return projectRequest<"method" | "data", T, HomeCategoryHeadsParams>({
options,
url: "/home/category/head",
config: {
data: {
vip: true,
},
method: "get",
},
});
}
使用接口
如下:
详情
ts
import { test } from "vitest";
import { homeCategoryHead } from "./homeCategoryHead";
test("使用homeCategoryHead接口", async () => {
const { execute, data } = homeCategoryHead({
onSuccess(data) {
console.log(` 在 onSuccess 回调内, 输出结果? `, data.result);
},
});
await execute({
data: {
vip: true,
},
});
console.log(` 输出结果? `, data.value?.result);
});