@ahoo-wang/fetcher-decorator 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,272 @@
1
+ # @ahoo-wang/fetcher-decorator
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@ahoo-wang/fetcher-decorator.svg)](https://www.npmjs.com/package/@ahoo-wang/fetcher-decorator)
4
+ [![Build Status](https://github.com/Ahoo-Wang/fetcher/actions/workflows/ci.yml/badge.svg)](https://github.com/Ahoo-Wang/fetcher/actions)
5
+ [![codecov](https://codecov.io/gh/Ahoo-Wang/fetcher/graph/badge.svg?token=JGiWZ52CvJ)](https://codecov.io/gh/Ahoo-Wang/fetcher)
6
+ [![License](https://img.shields.io/npm/l/@ahoo-wang/fetcher-decorator.svg)](https://github.com/Ahoo-Wang/fetcher/blob/main/LICENSE)
7
+ [![npm downloads](https://img.shields.io/npm/dm/@ahoo-wang/fetcher-decorator.svg)](https://www.npmjs.com/package/@ahoo-wang/fetcher-decorator)
8
+
9
+ Fetcher HTTP 客户端的装饰器支持。使用 TypeScript 装饰器实现简洁、声明式的 API 服务定义。
10
+
11
+ ## 🌟 功能特性
12
+
13
+ - **🎨 简洁的 API 定义**:使用直观的装饰器定义 HTTP 服务
14
+ - **🧭 自动参数绑定**:路径、查询、头部和请求体参数自动绑定
15
+ - **⏱️ 可配置超时**:支持每方法和每类的超时设置
16
+ - **🔗 Fetcher 集成**:与 Fetcher 的命名 fetcher 系统无缝集成
17
+ - **🛡️ TypeScript 支持**:完整的 TypeScript 类型定义
18
+ - **⚡ 自动实现**:方法自动实现为 HTTP 调用
19
+ - **📦 元数据系统**:丰富的元数据支持,用于高级定制
20
+
21
+ ## 🚀 快速开始
22
+
23
+ ### 安装
24
+
25
+ ```bash
26
+ # 使用 npm
27
+ npm install @ahoo-wang/fetcher-decorator
28
+
29
+ # 使用 pnpm
30
+ pnpm add @ahoo-wang/fetcher-decorator
31
+
32
+ # 使用 yarn
33
+ yarn add @ahoo-wang/fetcher-decorator
34
+ ```
35
+
36
+ ### 基本用法
37
+
38
+ ```typescript
39
+ import { NamedFetcher, fetcherRegistrar } from '@ahoo-wang/fetcher';
40
+ import {
41
+ api,
42
+ get,
43
+ post,
44
+ path,
45
+ query,
46
+ body,
47
+ } from '@ahoo-wang/fetcher-decorator';
48
+
49
+ // 创建并注册 fetcher
50
+ const userFetcher = new NamedFetcher('user', {
51
+ baseURL: 'https://api.user-service.com',
52
+ });
53
+
54
+ // 使用装饰器定义服务类
55
+ @api('/users', { fetcher: 'user', timeout: 10000 })
56
+ class UserService {
57
+ @post('/', { timeout: 5000 })
58
+ createUser(@body() user: User): Promise<Response> {
59
+ throw new Error('实现将自动生成');
60
+ }
61
+
62
+ @get('/{id}')
63
+ getUser(
64
+ @path('id') id: number,
65
+ @query('include') include: string,
66
+ ): Promise<Response> {
67
+ throw new Error('实现将自动生成');
68
+ }
69
+ }
70
+
71
+ // 使用服务
72
+ const userService = new UserService();
73
+ const response = await userService.createUser({ name: 'John' });
74
+ ```
75
+
76
+ ## 📚 API 参考
77
+
78
+ ### 类装饰器
79
+
80
+ #### `@api(basePath, metadata)`
81
+
82
+ 为类定义 API 元数据。
83
+
84
+ **参数:**
85
+
86
+ - `basePath`: 类中所有端点的基础路径
87
+ - `metadata`: API 的额外元数据
88
+ - `headers`: 类中所有请求的默认头部
89
+ - `timeout`: 类中所有请求的默认超时时间
90
+ - `fetcher`: 要使用的 fetcher 实例名称(默认:'default')
91
+
92
+ **示例:**
93
+
94
+ ```typescript
95
+
96
+ @api('/api/v1', {
97
+ headers: { 'X-API-Version': '1.0' },
98
+ timeout: 5000,
99
+ fetcher: 'api',
100
+ })
101
+ class ApiService {
102
+ // ...
103
+ }
104
+ ```
105
+
106
+ ### 方法装饰器
107
+
108
+ #### `@get(path, metadata)`
109
+
110
+ 定义 GET 端点。
111
+
112
+ #### `@post(path, metadata)`
113
+
114
+ 定义 POST 端点。
115
+
116
+ #### `@put(path, metadata)`
117
+
118
+ 定义 PUT 端点。
119
+
120
+ #### `@del(path, metadata)`
121
+
122
+ 定义 DELETE 端点。
123
+
124
+ #### `@patch(path, metadata)`
125
+
126
+ 定义 PATCH 端点。
127
+
128
+ #### `@head(path, metadata)`
129
+
130
+ 定义 HEAD 端点。
131
+
132
+ #### `@options(path, metadata)`
133
+
134
+ 定义 OPTIONS 端点。
135
+
136
+ **通用参数:**
137
+
138
+ - `path`: 端点路径(相对于类基础路径)
139
+ - `metadata`: 端点的额外元数据
140
+ - `headers`: 请求的头部
141
+ - `timeout`: 请求的超时时间
142
+ - `fetcher`: 要使用的 fetcher 实例名称
143
+
144
+ **示例:**
145
+
146
+ ```typescript
147
+ class UserService {
148
+ @get('/{id}', { timeout: 3000 })
149
+ getUser(@path('id') id: number): Promise<Response> {
150
+ throw new Error('实现将自动生成');
151
+ }
152
+
153
+ @post('/', { headers: { 'Content-Type': 'application/json' } })
154
+ createUser(@body() user: User): Promise<Response> {
155
+ throw new Error('实现将自动生成');
156
+ }
157
+ }
158
+ ```
159
+
160
+ ### 参数装饰器
161
+
162
+ #### `@path(name)`
163
+
164
+ 定义路径参数。
165
+
166
+ **参数:**
167
+
168
+ - `name`: 参数名称(在路径模板中使用)
169
+
170
+ #### `@query(name)`
171
+
172
+ 定义查询参数。
173
+
174
+ **参数:**
175
+
176
+ - `name`: 参数名称(在查询字符串中使用)
177
+
178
+ #### `@body()`
179
+
180
+ 定义请求体。
181
+
182
+ #### `@header(name)`
183
+
184
+ 定义头部参数。
185
+
186
+ **参数:**
187
+
188
+ - `name`: 头部名称
189
+
190
+ **示例:**
191
+
192
+ ```typescript
193
+ class UserService {
194
+ @get('/search')
195
+ searchUsers(
196
+ @query('q') query: string,
197
+ @query('limit') limit: number,
198
+ @header('Authorization') auth: string,
199
+ ): Promise<Response> {
200
+ throw new Error('实现将自动生成');
201
+ }
202
+
203
+ @put('/{id}')
204
+ updateUser(@path('id') id: number, @body() user: User): Promise<Response> {
205
+ throw new Error('实现将自动生成');
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## 🛠️ 高级用法
211
+
212
+ ### 继承支持
213
+
214
+ ```typescript
215
+
216
+ @api('/base')
217
+ class BaseService {
218
+ @get('/status')
219
+ getStatus(): Promise<Response> {
220
+ throw new Error('实现将自动生成');
221
+ }
222
+ }
223
+
224
+ @api('/users')
225
+ class UserService extends BaseService {
226
+ @get('/{id}')
227
+ getUser(@path('id') id: number): Promise<Response> {
228
+ throw new Error('实现将自动生成');
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### 复杂参数处理
234
+
235
+ ```typescript
236
+
237
+ @api('/api')
238
+ class ComplexService {
239
+ @post('/batch')
240
+ batchOperation(
241
+ @body() items: Item[],
242
+ @header('X-Request-ID') requestId: string,
243
+ @query('dryRun') dryRun: boolean = false,
244
+ ): Promise<Response> {
245
+ throw new Error('实现将自动生成');
246
+ }
247
+ }
248
+ ```
249
+
250
+ ## 🧪 测试
251
+
252
+ ```bash
253
+ # 运行测试
254
+ pnpm test
255
+
256
+ # 运行带覆盖率的测试
257
+ pnpm test --coverage
258
+ ```
259
+
260
+ ## 🤝 贡献
261
+
262
+ 欢迎贡献!请查看 [贡献指南](https://github.com/Ahoo-Wang/fetcher/blob/main/CONTRIBUTING.md) 了解更多详情。
263
+
264
+ ## 📄 许可证
265
+
266
+ Apache-2.0
267
+
268
+ ---
269
+
270
+ <p align="center">
271
+ Fetcher 生态系统的一部分
272
+ </p>
@@ -0,0 +1,42 @@
1
+ import { HeadersCapable, TimeoutCapable } from '@ahoo-wang/fetcher';
2
+ /**
3
+ * Metadata for class-level API configuration
4
+ *
5
+ * This interface defines the configuration options that can be applied to an entire API class.
6
+ * These settings will be used as defaults for all endpoints within the class unless overridden
7
+ * at the method level.
8
+ */
9
+ export interface ApiMetadata extends TimeoutCapable, HeadersCapable {
10
+ /**
11
+ * Base path for all endpoints in the class
12
+ *
13
+ * This path will be prepended to all endpoint paths defined in the class.
14
+ * For example, if basePath is '/api/v1' and an endpoint has path '/users',
15
+ * the full path will be '/api/v1/users'.
16
+ */
17
+ basePath?: string;
18
+ /**
19
+ * Default headers for all requests in the class
20
+ *
21
+ * These headers will be included in every request made by methods in this class.
22
+ * They can be overridden or extended at the method level.
23
+ */
24
+ headers?: Record<string, string>;
25
+ /**
26
+ * Default timeout for all requests in the class (in milliseconds)
27
+ *
28
+ * This timeout value will be applied to all requests made by methods in this class.
29
+ * Individual methods can specify their own timeout values to override this default.
30
+ */
31
+ timeout?: number;
32
+ /**
33
+ * Name of the fetcher instance to use, default: 'default'
34
+ *
35
+ * This allows you to specify which fetcher instance should be used for requests
36
+ * from this API class. The fetcher must be registered with the FetcherRegistrar.
37
+ */
38
+ fetcher?: string;
39
+ }
40
+ export declare const API_METADATA_KEY: unique symbol;
41
+ export declare function api(basePath?: string, metadata?: Omit<ApiMetadata, 'basePath'>): (constructor: Function) => void;
42
+ //# sourceMappingURL=apiDecorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiDecorator.d.ts","sourceRoot":"","sources":["../src/apiDecorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpE,OAAO,kBAAkB,CAAC;AAE1B;;;;;;GAMG;AACH,MAAM,WAAW,WAAY,SAAQ,cAAc,EAAE,cAAc;IACjE;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,eAAyB,CAAC;AAgEvD,wBAAgB,GAAG,CACjB,QAAQ,GAAE,MAAW,EACrB,QAAQ,GAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAM,IAE5B,aAAa,QAAQ,UActC"}
@@ -0,0 +1,58 @@
1
+ import { HttpMethod } from '@ahoo-wang/fetcher';
2
+ import { ApiMetadata } from './apiDecorator';
3
+ /**
4
+ * Metadata for HTTP endpoints
5
+ *
6
+ * This interface defines the configuration options for individual HTTP endpoints (methods).
7
+ * These settings will override any corresponding class-level settings from ApiMetadata.
8
+ */
9
+ export interface EndpointMetadata extends ApiMetadata {
10
+ /**
11
+ * HTTP method for the endpoint
12
+ *
13
+ * Specifies the HTTP verb to be used for this endpoint (GET, POST, PUT, DELETE, etc.)
14
+ */
15
+ method: HttpMethod;
16
+ /**
17
+ * Path for the endpoint (relative to class base path)
18
+ *
19
+ * This path will be appended to the class's base path to form the complete URL.
20
+ * Path parameters can be specified using curly braces, e.g., '/users/{id}'
21
+ */
22
+ path?: string;
23
+ }
24
+ export declare const ENDPOINT_METADATA_KEY: unique symbol;
25
+ export type MethodEndpointMetadata = Omit<EndpointMetadata, 'method' | 'path'>;
26
+ /**
27
+ * Decorator factory for defining HTTP endpoints
28
+ *
29
+ * This function creates a decorator that can be used to define HTTP endpoints
30
+ * on class methods. It stores metadata about the endpoint that will be used
31
+ * to generate the actual HTTP request.
32
+ *
33
+ * @param method - The HTTP method for this endpoint
34
+ * @param path - The path for this endpoint (relative to class base path)
35
+ * @param metadata - Additional endpoint metadata (headers, timeout, etc.)
36
+ * @returns A method decorator function
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * @api('/api/v1')
41
+ * class UserService {
42
+ * @endpoint(HttpMethod.GET, '/users/{id}')
43
+ * getUser(@path('id') id: string): Promise<Response> {
44
+ * // Implementation will be generated automatically
45
+ * throw autoGeneratedError();
46
+ * }
47
+ * }
48
+ * ```
49
+ */
50
+ export declare function endpoint(method: HttpMethod, path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
51
+ export declare function get(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
52
+ export declare function post(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
53
+ export declare function put(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
54
+ export declare function del(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
55
+ export declare function patch(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
56
+ export declare function head(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
57
+ export declare function options(path?: string, metadata?: MethodEndpointMetadata): (target: any, propertyKey: string) => void;
58
+ //# sourceMappingURL=endpointDecorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpointDecorator.d.ts","sourceRoot":"","sources":["../src/endpointDecorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,kBAAkB,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;OAIG;IACH,MAAM,EAAE,UAAU,CAAC;IAEnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,qBAAqB,eAA8B,CAAC;AAEjE,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,UAAU,EAClB,IAAI,GAAE,MAAW,EACjB,QAAQ,GAAE,sBAA2B,IAErB,QAAQ,GAAG,EAAE,aAAa,MAAM,KAAG,IAAI,CAcxD;AAED,wBAAgB,GAAG,CAAC,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,sBAA2B,YAhBlD,GAAG,eAAe,MAAM,KAAG,IAAI,CAkBxD;AAED,wBAAgB,IAAI,CAAC,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,sBAA2B,YApBnD,GAAG,eAAe,MAAM,KAAG,IAAI,CAsBxD;AAED,wBAAgB,GAAG,CAAC,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,sBAA2B,YAxBlD,GAAG,eAAe,MAAM,KAAG,IAAI,CA0BxD;AAED,wBAAgB,GAAG,CAAC,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,sBAA2B,YA5BlD,GAAG,eAAe,MAAM,KAAG,IAAI,CA8BxD;AAED,wBAAgB,KAAK,CACnB,IAAI,GAAE,MAAW,EACjB,QAAQ,GAAE,sBAA2B,YAlCb,GAAG,eAAe,MAAM,KAAG,IAAI,CAqCxD;AAED,wBAAgB,IAAI,CAAC,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,sBAA2B,YAvCnD,GAAG,eAAe,MAAM,KAAG,IAAI,CAyCxD;AAED,wBAAgB,OAAO,CACrB,IAAI,GAAE,MAAW,EACjB,QAAQ,GAAE,sBAA2B,YA7Cb,GAAG,eAAe,MAAM,KAAG,IAAI,CAgDxD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * AutoGenerated is a custom error class that indicates
3
+ * a method implementation will be automatically generated.
4
+ *
5
+ * @example
6
+ * ```
7
+ * @post()
8
+ * createUser(@body() user: User):Promise<Response> {
9
+ * throw autoGeneratedError();
10
+ * }
11
+ * ```
12
+ */
13
+ /**
14
+ * AutoGenerated is a custom error class that indicates
15
+ * a method implementation will be automatically generated.
16
+ */
17
+ export declare class AutoGenerated extends Error {
18
+ constructor();
19
+ }
20
+ /**
21
+ * Factory function to create an AutoGenerated instance.
22
+ *
23
+ * @returns {AutoGenerated} A new AutoGenerated instance
24
+ */
25
+ export declare const autoGeneratedError: () => AutoGenerated;
26
+ //# sourceMappingURL=generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generated.d.ts","sourceRoot":"","sources":["../src/generated.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;GAWG;AACH;;;GAGG;AACH,qBAAa,aAAc,SAAQ,KAAK;;CAKvC;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAO,aAErC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from './apiDecorator';
2
+ export * from './endpointDecorator';
3
+ export * from './parameterDecorator';
4
+ export * from './reflection';
5
+ export * from './requestExecutor';
6
+ export * from './generated';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC"}