feat(reset): 以构造器模式重构
- 加了大文件传输自定义分片协议 BREAKING CHANGES: 0.1.0(latest)
This commit is contained in:
128
decorators/common.ts
Normal file
128
decorators/common.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { setMeta, getMeta, type ApiMethodMeta } from './meta';
|
||||
import { AxiosHttpClient, type BaseError } from '../client';
|
||||
|
||||
// ApiError错误接口
|
||||
export interface ApiError {
|
||||
status: number; // 状态码(来自response的status)
|
||||
statusText: string; // 状态文本(来自response的msg)
|
||||
code: string; // 错误码(字符串)
|
||||
message: string; // 报错信息(字符串)
|
||||
// 没有别的细节了,错误码直接对照常量映射
|
||||
}
|
||||
|
||||
// 客户端请求参数接口
|
||||
export interface ClientRequestParams {
|
||||
method: string;
|
||||
url: string;
|
||||
query?: Record<string, string | number>;
|
||||
body?: any;
|
||||
}
|
||||
|
||||
// 创建 AxiosHttpClient 单例实例
|
||||
const apiClientInstance = new AxiosHttpClient();
|
||||
|
||||
/**
|
||||
* 创建 HTTP 方法装饰器的通用函数
|
||||
* @param method HTTP 方法类型
|
||||
* @returns 装饰器函数
|
||||
*/
|
||||
export function createHttpMethodDecorator(method: ApiMethodMeta['method']) {
|
||||
return function(path: string) {
|
||||
return function(_target: Object, context: ClassMethodDecoratorContext) {
|
||||
// 确保只应用于方法
|
||||
if (context.kind !== 'method') {
|
||||
throw new Error(`HTTP method decorator (${method}) can only be applied to methods`);
|
||||
}
|
||||
|
||||
// 获取原始方法
|
||||
const originalMethod = _target[context.name as keyof Object] as Function;
|
||||
|
||||
// 设置元数据
|
||||
setMeta(originalMethod, 'api', {
|
||||
method,
|
||||
path
|
||||
} as ApiMethodMeta);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 为 API 客户端类绑定 HTTP 客户端实例的装饰器
|
||||
* @description 该装饰器对当前类注入 AxiosHttpClient 实例
|
||||
*/
|
||||
export function ApiClientBound<T extends { new (...args: any[]): { client: AxiosHttpClient } }>(target: T, _context: ClassDecoratorContext<T>) {
|
||||
// 定义一个新类,继承自目标类
|
||||
return class extends target {
|
||||
// 在构造函数中初始化客户端实例
|
||||
constructor(...args: any[]) {
|
||||
super(...args);
|
||||
// 添加客户端实例
|
||||
this.client = apiClientInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求执行装饰器,自动处理 API 调用逻辑
|
||||
*/
|
||||
export function Request(target: Object, context: ClassMethodDecoratorContext) {
|
||||
const methodName = String(context.name);
|
||||
|
||||
// 确保只应用于方法
|
||||
if (context.kind !== 'method') {
|
||||
throw new Error('Request decorator can only be applied to methods');
|
||||
}
|
||||
|
||||
// 保存原始方法
|
||||
const originalMethod = target[context.name as keyof Object] as Function;
|
||||
|
||||
// 定义新的方法实现
|
||||
async function replacementMethod(this: { client: { request: (params: ClientRequestParams) => Promise<any> } }, ...args: any[]) {
|
||||
// 获取 API 元数据
|
||||
const meta = getMeta(originalMethod, 'api') as ApiMethodMeta | undefined;
|
||||
if (!meta) {
|
||||
throw new Error(`Missing API metadata on ${methodName}. Please use an HTTP method decorator (GET, POST, etc.)`);
|
||||
}
|
||||
|
||||
const { method, path } = meta;
|
||||
|
||||
// 处理请求参数
|
||||
const params = args[0] ?? {};
|
||||
const body = args[1];
|
||||
|
||||
// 替换路径中的动态参数段
|
||||
let finalPath = path.replace(/:([\w]+)/g, (_, key) => {
|
||||
const paramValue = params[key];
|
||||
if (paramValue === undefined) {
|
||||
throw new Error(`Missing required path parameter '${key}' for API endpoint '${path}'`);
|
||||
}
|
||||
return String(paramValue);
|
||||
});
|
||||
|
||||
// 执行请求并处理错误
|
||||
try {
|
||||
return await this.client.request({
|
||||
method,
|
||||
url: finalPath,
|
||||
query: params,
|
||||
body,
|
||||
});
|
||||
} catch (error: BaseError | any) {
|
||||
// 确保错误对象符合 ApiError 接口
|
||||
const apiError: ApiError = {
|
||||
status: error.response?.status || 500,
|
||||
statusText: error.response?.msg || 'Internal Server Error',
|
||||
code: error?.code || 'UNKNOWN_ERROR',
|
||||
message: error?.message || 'An unexpected error occurred',
|
||||
};
|
||||
throw apiError;
|
||||
}
|
||||
}
|
||||
|
||||
// TS5+直接返回新方法定义
|
||||
return replacementMethod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user