Skip to content

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);
});

贡献者

The avatar of contributor named as ruan-cat ruan-cat

页面历史