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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
41
decorators/http-methods.ts
Normal file
41
decorators/http-methods.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { createHttpMethodDecorator } from './common';
|
||||
|
||||
/**
|
||||
* GET 请求装饰器
|
||||
* @param path API 路径,支持 :param 格式的动态参数
|
||||
*/
|
||||
export function GET(path: string) {
|
||||
return createHttpMethodDecorator('GET')(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST 请求装饰器
|
||||
* @param path API 路径,支持 :param 格式的动态参数
|
||||
*/
|
||||
export function POST(path: string) {
|
||||
return createHttpMethodDecorator('POST')(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT 请求装饰器
|
||||
* @param path API 路径,支持 :param 格式的动态参数
|
||||
*/
|
||||
export function PUT(path: string) {
|
||||
return createHttpMethodDecorator('PUT')(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE 请求装饰器
|
||||
* @param path API 路径,支持 :param 格式的动态参数
|
||||
*/
|
||||
export function DELETE(path: string) {
|
||||
return createHttpMethodDecorator('DELETE')(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH 请求装饰器
|
||||
* @param path API 路径,支持 :param 格式的动态参数
|
||||
*/
|
||||
export function PATCH(path: string) {
|
||||
return createHttpMethodDecorator('PATCH')(path);
|
||||
}
|
||||
2
decorators/index.ts
Normal file
2
decorators/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './http-methods';
|
||||
export * from './common';
|
||||
35
decorators/meta.ts
Normal file
35
decorators/meta.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* API 方法元数据接口
|
||||
*/
|
||||
export interface ApiMethodMeta {
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
path: string;
|
||||
}
|
||||
|
||||
// 使用 WeakMap 存储元数据,避免内存泄漏
|
||||
const metaStore = new WeakMap<Function, Map<string, ApiMethodMeta>>();
|
||||
|
||||
/**
|
||||
* 设置函数的元数据
|
||||
* @param target 目标函数
|
||||
* @param key 元数据键名
|
||||
* @param value 元数据值
|
||||
*/
|
||||
export function setMeta(target: Function, _key: string, value: ApiMethodMeta): void {
|
||||
let map = metaStore.get(target);
|
||||
if (!map) {
|
||||
map = new Map();
|
||||
metaStore.set(target, map);
|
||||
}
|
||||
map.set(_key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的元数据
|
||||
* @param target 目标函数
|
||||
* @param key 元数据键名
|
||||
* @returns 元数据值或undefined
|
||||
*/
|
||||
export function getMeta(target: Function, key: string): ApiMethodMeta | undefined {
|
||||
return metaStore.get(target)?.get(key);
|
||||
}
|
||||
Reference in New Issue
Block a user