@ticatec/restful_service_api 0.2.1 → 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.
- package/README-CN.md +229 -54
- package/README.md +221 -48
- package/dist/ApiError.d.ts +17 -0
- package/dist/ApiError.js +17 -0
- package/dist/FileService.d.ts +92 -0
- package/dist/FileService.js +1 -0
- package/dist/RestService.d.ts +128 -54
- package/dist/RestService.js +12 -0
- package/dist/UploadCallback.d.ts +16 -16
- package/dist/index.d.ts +3 -0
- package/package.json +3 -2
package/README-CN.md
CHANGED
|
@@ -14,7 +14,37 @@
|
|
|
14
14
|
- 🛡️ **错误处理**: 内置错误处理机制,包含自定义 ApiError 类
|
|
15
15
|
- ⚡ **拦截器**: 支持请求前后拦截器,用于身份验证和数据处理
|
|
16
16
|
- 🎯 **灵活性**: 支持自定义请求头、超时设置和数据处理器
|
|
17
|
+
- 📁 **文件操作**: 专用的文件上传/下载接口
|
|
17
18
|
- 🌐 **浏览器优先**: 专为前端应用程序设计
|
|
19
|
+
- ✨ **PATCH 支持**: 完整支持 HTTP PATCH 方法进行部分更新
|
|
20
|
+
|
|
21
|
+
## ⚠️ v0.5.0 重大变更
|
|
22
|
+
|
|
23
|
+
**从 0.5.0 版本开始,此包已迁移到 ESM (ECMAScript Modules) 格式。**
|
|
24
|
+
|
|
25
|
+
### 对您的影响
|
|
26
|
+
|
|
27
|
+
- 您的项目必须使用 ESM 格式(package.json 中包含 `"type": "module"` 或使用 `.mjs` 扩展名)
|
|
28
|
+
- 不再支持 `require()`,请使用 `import` 语句
|
|
29
|
+
|
|
30
|
+
### 迁移指南
|
|
31
|
+
|
|
32
|
+
如果您正在从 0.5.0 之前的版本升级:
|
|
33
|
+
|
|
34
|
+
**之前 (CommonJS):**
|
|
35
|
+
```javascript
|
|
36
|
+
const RestService = require('@ticatec/restful_service_api');
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**之后 (ESM):**
|
|
40
|
+
```typescript
|
|
41
|
+
import RestService from '@ticatec/restful_service_api';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
对于 CommonJS 项目,您可能需要使用动态导入:
|
|
45
|
+
```javascript
|
|
46
|
+
const { default: RestService } = await import('@ticatec/restful_service_api');
|
|
47
|
+
```
|
|
18
48
|
|
|
19
49
|
## 安装
|
|
20
50
|
|
|
@@ -25,7 +55,7 @@ npm install @ticatec/restful_service_api
|
|
|
25
55
|
## 快速开始
|
|
26
56
|
|
|
27
57
|
```typescript
|
|
28
|
-
import RestService from '@ticatec/restful_service_api';
|
|
58
|
+
import RestService, { FileService } from '@ticatec/restful_service_api';
|
|
29
59
|
|
|
30
60
|
// 实现 RestService 接口
|
|
31
61
|
class MyApiClient implements RestService {
|
|
@@ -37,42 +67,78 @@ class MyApiClient implements RestService {
|
|
|
37
67
|
// 在这里实现
|
|
38
68
|
}
|
|
39
69
|
|
|
70
|
+
async patch(url: string, data?: any, options?: RestfulOptions) {
|
|
71
|
+
// 在这里实现
|
|
72
|
+
}
|
|
73
|
+
|
|
40
74
|
// ... 其他方法
|
|
41
75
|
}
|
|
42
76
|
|
|
77
|
+
// 实现 FileService 接口
|
|
78
|
+
class MyFileClient implements FileService {
|
|
79
|
+
async upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor) {
|
|
80
|
+
// 在这里实现
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string) {
|
|
84
|
+
// 在这里实现
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async download(url: string, filename: string, params: any, method?: string, formData?: any) {
|
|
88
|
+
// 在这里实现
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
43
92
|
const api = new MyApiClient();
|
|
93
|
+
const fileApi = new MyFileClient();
|
|
44
94
|
|
|
45
|
-
//
|
|
95
|
+
// 发起 REST 请求
|
|
46
96
|
const users = await api.get('/users');
|
|
47
97
|
const newUser = await api.post('/users', { name: '张三' });
|
|
98
|
+
const partialUpdate = await api.patch('/users/1', { status: 'active' });
|
|
99
|
+
|
|
100
|
+
// 文件操作
|
|
101
|
+
const result = await fileApi.upload('/upload', { userId: 123 }, file);
|
|
48
102
|
```
|
|
49
103
|
|
|
50
104
|
## API 参考
|
|
51
105
|
|
|
52
106
|
### RestService 接口
|
|
53
107
|
|
|
54
|
-
|
|
108
|
+
用于标准 HTTP REST 操作的主要接口:
|
|
55
109
|
|
|
56
110
|
```typescript
|
|
57
111
|
interface RestService {
|
|
58
112
|
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
59
113
|
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
60
114
|
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
115
|
+
patch(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
61
116
|
del(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### FileService 接口
|
|
121
|
+
|
|
122
|
+
专用于文件上传和下载操作的接口:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
interface FileService {
|
|
62
126
|
upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
|
|
63
127
|
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
|
|
64
128
|
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
|
|
65
129
|
}
|
|
66
130
|
```
|
|
67
131
|
|
|
68
|
-
###
|
|
132
|
+
### RestService 方法
|
|
69
133
|
|
|
70
134
|
#### `get(url, params?, dataProcessor?)`
|
|
135
|
+
执行 HTTP GET 请求获取资源。
|
|
71
136
|
- **url**: 接口端点 URL
|
|
72
137
|
- **params**: 查询参数(可选)
|
|
73
138
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
74
139
|
|
|
75
140
|
#### `post(url, data?, options?)`
|
|
141
|
+
执行 HTTP POST 请求创建新资源。
|
|
76
142
|
- **url**: 接口端点 URL
|
|
77
143
|
- **data**: 请求载荷(可选)
|
|
78
144
|
- **options**: 可选的配置对象,包含:
|
|
@@ -81,20 +147,36 @@ interface RestService {
|
|
|
81
147
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
82
148
|
|
|
83
149
|
#### `put(url, data?, options?)`
|
|
84
|
-
|
|
150
|
+
执行 HTTP PUT 请求更新整个资源。
|
|
151
|
+
- **url**: 接口端点 URL
|
|
152
|
+
- **data**: 请求载荷(可选)
|
|
153
|
+
- **options**: 可选的配置对象,包含:
|
|
154
|
+
- **params**: 查询参数(可选)
|
|
155
|
+
- **contentType**: Content-Type 请求头(可选,默认为 application/json)
|
|
156
|
+
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
157
|
+
|
|
158
|
+
#### `patch(url, data?, options?)`
|
|
159
|
+
执行 HTTP PATCH 请求部分更新资源。
|
|
160
|
+
- **url**: 接口端点 URL
|
|
161
|
+
- **data**: 包含要更新字段的请求载荷(可选)
|
|
85
162
|
- **options**: 可选的配置对象,包含:
|
|
86
163
|
- **params**: 查询参数(可选)
|
|
87
164
|
- **contentType**: Content-Type 请求头(可选,默认为 application/json)
|
|
88
165
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
89
166
|
|
|
90
167
|
#### `del(url, data?, options?)`
|
|
91
|
-
|
|
168
|
+
执行 HTTP DELETE 请求删除资源。
|
|
169
|
+
- **url**: 接口端点 URL
|
|
170
|
+
- **data**: 请求体数据(可选)
|
|
92
171
|
- **options**: 可选的配置对象,包含:
|
|
93
172
|
- **params**: 查询参数(可选)
|
|
94
173
|
- **contentType**: Content-Type 请求头(可选,默认为 application/json)
|
|
95
174
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
96
175
|
|
|
176
|
+
### FileService 方法
|
|
177
|
+
|
|
97
178
|
#### `upload(url, params, file, fileKey?, dataProcessor?)`
|
|
179
|
+
执行同步文件上传操作。
|
|
98
180
|
- **url**: 上传端点 URL
|
|
99
181
|
- **params**: 上传请求的附加参数
|
|
100
182
|
- **file**: 要上传的文件对象
|
|
@@ -102,6 +184,7 @@ interface RestService {
|
|
|
102
184
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
103
185
|
|
|
104
186
|
#### `asyncUpload(url, params, file, callback, fileKey?)`
|
|
187
|
+
执行异步文件上传,支持进度监控和取消功能。
|
|
105
188
|
- **url**: 上传端点 URL
|
|
106
189
|
- **params**: 上传请求的附加参数
|
|
107
190
|
- **file**: 要上传的文件对象
|
|
@@ -110,6 +193,7 @@ interface RestService {
|
|
|
110
193
|
- **返回值**: 返回 Promise,解析为 UploadProgress 对象,可用于取消上传
|
|
111
194
|
|
|
112
195
|
#### `download(url, filename, params, method?, formData?)`
|
|
196
|
+
执行文件下载操作。
|
|
113
197
|
- **url**: 下载端点 URL
|
|
114
198
|
- **filename**: 保存下载文件的名称
|
|
115
199
|
- **params**: 下载请求参数
|
|
@@ -202,13 +286,16 @@ await api.post('/upload', data, {}, { contentType: TYPE_JSON });
|
|
|
202
286
|
|
|
203
287
|
以下是使用原生 fetch API 的完整实现示例:
|
|
204
288
|
|
|
289
|
+
### RestService 实现
|
|
290
|
+
|
|
205
291
|
```typescript
|
|
206
292
|
import RestService, {
|
|
207
293
|
ApiError,
|
|
208
294
|
PreInterceptor,
|
|
209
295
|
PostInterceptor,
|
|
210
296
|
RestfulOptions,
|
|
211
|
-
TYPE_JSON
|
|
297
|
+
TYPE_JSON,
|
|
298
|
+
DataProcessor
|
|
212
299
|
} from '@ticatec/restful_service_api';
|
|
213
300
|
|
|
214
301
|
class FetchRestService implements RestService {
|
|
@@ -241,6 +328,13 @@ class FetchRestService implements RestService {
|
|
|
241
328
|
return this.request('PUT', url + queryString, data, contentType, options?.dataProcessor);
|
|
242
329
|
}
|
|
243
330
|
|
|
331
|
+
async patch(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
332
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
333
|
+
const params = options?.params;
|
|
334
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
335
|
+
return this.request('PATCH', url + queryString, data, contentType, options?.dataProcessor);
|
|
336
|
+
}
|
|
337
|
+
|
|
244
338
|
async del(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
245
339
|
const contentType = options?.contentType || TYPE_JSON;
|
|
246
340
|
const params = options?.params;
|
|
@@ -298,60 +392,140 @@ class FetchRestService implements RestService {
|
|
|
298
392
|
const api = new FetchRestService('https://api.example.com');
|
|
299
393
|
const users = await api.get('/users');
|
|
300
394
|
const newUser = await api.post('/users', { name: '张三' });
|
|
301
|
-
const
|
|
395
|
+
const partialUpdate = await api.patch('/users/1', { status: 'active' });
|
|
396
|
+
const fullUpdate = await api.put('/users/1', { name: '李四', age: 30 });
|
|
302
397
|
```
|
|
303
398
|
|
|
304
|
-
###
|
|
399
|
+
### FileService 实现
|
|
305
400
|
|
|
306
401
|
```typescript
|
|
307
|
-
import
|
|
308
|
-
UploadCallback,
|
|
309
|
-
UploadProgress
|
|
310
|
-
} from '@ticatec/restful_service_api';
|
|
402
|
+
import FileService, { UploadCallback, UploadProgress, DataProcessor } from '@ticatec/restful_service_api';
|
|
311
403
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const file = fileInput.files[0];
|
|
404
|
+
class FetchFileService implements FileService {
|
|
405
|
+
private baseURL: string;
|
|
315
406
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
} catch (error) {
|
|
320
|
-
console.error('上传失败:', error);
|
|
321
|
-
}
|
|
407
|
+
constructor(baseURL: string) {
|
|
408
|
+
this.baseURL = baseURL;
|
|
409
|
+
}
|
|
322
410
|
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
411
|
+
async upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any> {
|
|
412
|
+
const formData = new FormData();
|
|
413
|
+
formData.append(fileKey || 'file', file);
|
|
414
|
+
|
|
415
|
+
// 添加附加参数
|
|
416
|
+
Object.keys(params).forEach(key => {
|
|
417
|
+
formData.append(key, params[key]);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const response = await fetch(this.baseURL + url, {
|
|
421
|
+
method: 'POST',
|
|
422
|
+
body: formData
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
if (!response.ok) {
|
|
426
|
+
throw new Error(`上传失败: ${response.statusText}`);
|
|
334
427
|
}
|
|
335
|
-
};
|
|
336
428
|
|
|
337
|
-
const
|
|
429
|
+
const data = await response.json();
|
|
430
|
+
return dataProcessor ? dataProcessor(data) : data;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress> {
|
|
434
|
+
const formData = new FormData();
|
|
435
|
+
formData.append(fileKey || 'file', file);
|
|
338
436
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}, 5000);
|
|
437
|
+
Object.keys(params).forEach(key => {
|
|
438
|
+
formData.append(key, params[key]);
|
|
439
|
+
});
|
|
343
440
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
441
|
+
const xhr = new XMLHttpRequest();
|
|
442
|
+
|
|
443
|
+
return new Promise((resolve) => {
|
|
444
|
+
xhr.upload.addEventListener('progress', (e) => {
|
|
445
|
+
if (e.lengthComputable && callback.progressUpdate) {
|
|
446
|
+
callback.progressUpdate(e.loaded);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
xhr.addEventListener('load', () => {
|
|
451
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
452
|
+
const data = JSON.parse(xhr.responseText);
|
|
453
|
+
callback.onCompleted(data);
|
|
454
|
+
} else if (callback.handleError) {
|
|
455
|
+
callback.handleError(new Error(`上传失败: ${xhr.statusText}`));
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
xhr.addEventListener('error', () => {
|
|
460
|
+
if (callback.handleError) {
|
|
461
|
+
callback.handleError(new Error('网络错误'));
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
xhr.open(callback.method || 'POST', this.baseURL + url);
|
|
466
|
+
xhr.send(formData);
|
|
467
|
+
|
|
468
|
+
resolve({
|
|
469
|
+
cancel: () => xhr.abort()
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any> {
|
|
475
|
+
let fullUrl = this.baseURL + url;
|
|
476
|
+
|
|
477
|
+
if (method === 'POST' && formData) {
|
|
478
|
+
const form = new FormData();
|
|
479
|
+
Object.keys(formData).forEach(key => {
|
|
480
|
+
form.append(key, formData[key]);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
const response = await fetch(fullUrl, {
|
|
484
|
+
method: 'POST',
|
|
485
|
+
body: form
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
const blob = await response.blob();
|
|
489
|
+
const downloadUrl = window.URL.createObjectURL(blob);
|
|
490
|
+
const a = document.createElement('a');
|
|
491
|
+
a.href = downloadUrl;
|
|
492
|
+
a.download = filename;
|
|
493
|
+
a.click();
|
|
494
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
495
|
+
} else {
|
|
496
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
497
|
+
fullUrl += queryString;
|
|
498
|
+
|
|
499
|
+
const response = await fetch(fullUrl);
|
|
500
|
+
const blob = await response.blob();
|
|
501
|
+
const downloadUrl = window.URL.createObjectURL(blob);
|
|
502
|
+
const a = document.createElement('a');
|
|
503
|
+
a.href = downloadUrl;
|
|
504
|
+
a.download = filename;
|
|
505
|
+
a.click();
|
|
506
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
350
509
|
}
|
|
351
510
|
|
|
352
|
-
//
|
|
353
|
-
const
|
|
354
|
-
|
|
511
|
+
// 使用示例
|
|
512
|
+
const fileApi = new FetchFileService('https://api.example.com');
|
|
513
|
+
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
|
514
|
+
const file = fileInput.files[0];
|
|
515
|
+
|
|
516
|
+
// 简单上传
|
|
517
|
+
const result = await fileApi.upload('/upload', { userId: 123 }, file);
|
|
518
|
+
|
|
519
|
+
// 带进度跟踪的异步上传
|
|
520
|
+
const progress = await fileApi.asyncUpload('/upload', { userId: 123 }, file, {
|
|
521
|
+
method: 'POST',
|
|
522
|
+
progressUpdate: (loaded) => console.log(`已上传: ${loaded} 字节`),
|
|
523
|
+
onCompleted: (data) => console.log('完成!', data),
|
|
524
|
+
handleError: (err) => console.error('错误!', err)
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// 下载文件
|
|
528
|
+
await fileApi.download('/files/document.pdf', 'my-document.pdf', { userId: 123 });
|
|
355
529
|
```
|
|
356
530
|
|
|
357
531
|
## 工具函数
|
|
@@ -362,20 +536,20 @@ await api.download('/reports/generate', 'monthly-report.pdf', {}, 'POST', formDa
|
|
|
362
536
|
import utils from '@ticatec/restful_service_api/utils';
|
|
363
537
|
|
|
364
538
|
// 将对象转换为查询字符串
|
|
365
|
-
const queryString = utils.toQueryString({ name: '
|
|
366
|
-
// 返回: "name
|
|
539
|
+
const queryString = utils.toQueryString({ name: '张三', age: 30 });
|
|
540
|
+
// 返回: "name=张三&age=30"
|
|
367
541
|
|
|
368
542
|
// 将 URL 与参数组合
|
|
369
543
|
const fullUrl = utils.combineUrl('/api/users', { page: 1, limit: 10 });
|
|
370
544
|
// 返回: "/api/users?page=1&limit=10"
|
|
371
545
|
|
|
372
546
|
// 生成 HTTP 请求选项
|
|
373
|
-
const options = utils.generateRequestOptions('POST', { id: 1 }, { name: '
|
|
374
|
-
// 返回: { method: 'POST', headers: {}, params: { id: 1 }, data: { name: '
|
|
547
|
+
const options = utils.generateRequestOptions('POST', { id: 1 }, { name: '张三' });
|
|
548
|
+
// 返回: { method: 'POST', headers: {}, params: { id: 1 }, data: { name: '张三' } }
|
|
375
549
|
|
|
376
550
|
// 清理参数(移除 null、undefined、空字符串,修剪字符串值)
|
|
377
|
-
const cleanedParams = utils.cleanParams({ name: '
|
|
378
|
-
// 返回: { name: '
|
|
551
|
+
const cleanedParams = utils.cleanParams({ name: ' 张三 ', age: null, email: '' });
|
|
552
|
+
// 返回: { name: '张三' }
|
|
379
553
|
|
|
380
554
|
// 函数工具
|
|
381
555
|
utils.invokeFunction(callback, arg1, arg2); // 安全地调用函数(如果存在)
|
|
@@ -423,6 +597,7 @@ const api = new FetchRestService(
|
|
|
423
597
|
// 现在所有请求都会自动包含认证头
|
|
424
598
|
const profile = await api.get('/user/profile');
|
|
425
599
|
const updated = await api.put('/user/profile', { name: '新名称' });
|
|
600
|
+
const partial = await api.patch('/user/profile', { status: 'active' });
|
|
426
601
|
```
|
|
427
602
|
|
|
428
603
|
## 贡献
|
package/README.md
CHANGED
|
@@ -14,7 +14,36 @@ A lightweight TypeScript RESTful API client for browsers with comprehensive erro
|
|
|
14
14
|
- 🛡️ **Error Handling**: Built-in error handling with custom ApiError class
|
|
15
15
|
- ⚡ **Interceptors**: Pre and post request interceptors for authentication and data processing
|
|
16
16
|
- 🎯 **Flexible**: Support for custom headers, timeouts, and data processors
|
|
17
|
+
- 📁 **File Operations**: Dedicated interface for file upload/download operations
|
|
17
18
|
- 🌐 **Browser-First**: Designed specifically for frontend applications
|
|
19
|
+
- ✨ **PATCH Support**: Full support for HTTP PATCH method for partial updates
|
|
20
|
+
|
|
21
|
+
## ⚠️ Breaking Changes in v0.5.0
|
|
22
|
+
|
|
23
|
+
**Starting from version 0.5.0, this package has migrated to ESM (ECMAScript Modules) format.**
|
|
24
|
+
|
|
25
|
+
### What This Means for You
|
|
26
|
+
|
|
27
|
+
- Your project must use ESM format (have `"type": "module"` in package.json or use `.mjs` extension)
|
|
28
|
+
- `require()` is no longer supported. Use `import` statements instead
|
|
29
|
+
### Migration Guide
|
|
30
|
+
|
|
31
|
+
If you're upgrading from a version prior to 0.5.0:
|
|
32
|
+
|
|
33
|
+
**Before (CommonJS):**
|
|
34
|
+
```javascript
|
|
35
|
+
const RestService = require('@ticatec/restful_service_api');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**After (ESM):**
|
|
39
|
+
```typescript
|
|
40
|
+
import RestService from '@ticatec/restful_service_api';
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For CommonJS projects, you may need to use dynamic import:
|
|
44
|
+
```javascript
|
|
45
|
+
const { default: RestService } = await import('@ticatec/restful_service_api');
|
|
46
|
+
```
|
|
18
47
|
|
|
19
48
|
## Installation
|
|
20
49
|
|
|
@@ -25,7 +54,7 @@ npm install @ticatec/restful_service_api
|
|
|
25
54
|
## Quick Start
|
|
26
55
|
|
|
27
56
|
```typescript
|
|
28
|
-
import RestService from '@ticatec/restful_service_api';
|
|
57
|
+
import RestService, { FileService } from '@ticatec/restful_service_api';
|
|
29
58
|
|
|
30
59
|
// Your implementation of RestService interface
|
|
31
60
|
class MyApiClient implements RestService {
|
|
@@ -37,42 +66,78 @@ class MyApiClient implements RestService {
|
|
|
37
66
|
// Implementation here
|
|
38
67
|
}
|
|
39
68
|
|
|
69
|
+
async patch(url: string, data?: any, options?: RestfulOptions) {
|
|
70
|
+
// Implementation here
|
|
71
|
+
}
|
|
72
|
+
|
|
40
73
|
// ... other methods
|
|
41
74
|
}
|
|
42
75
|
|
|
76
|
+
// Your implementation of FileService interface
|
|
77
|
+
class MyFileClient implements FileService {
|
|
78
|
+
async upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor) {
|
|
79
|
+
// Implementation here
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string) {
|
|
83
|
+
// Implementation here
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async download(url: string, filename: string, params: any, method?: string, formData?: any) {
|
|
87
|
+
// Implementation here
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
43
91
|
const api = new MyApiClient();
|
|
92
|
+
const fileApi = new MyFileClient();
|
|
44
93
|
|
|
45
|
-
// Make requests
|
|
94
|
+
// Make REST requests
|
|
46
95
|
const users = await api.get('/users');
|
|
47
96
|
const newUser = await api.post('/users', { name: 'John Doe' });
|
|
97
|
+
const partialUpdate = await api.patch('/users/1', { status: 'active' });
|
|
98
|
+
|
|
99
|
+
// File operations
|
|
100
|
+
const result = await fileApi.upload('/upload', { userId: 123 }, file);
|
|
48
101
|
```
|
|
49
102
|
|
|
50
103
|
## API Reference
|
|
51
104
|
|
|
52
105
|
### RestService Interface
|
|
53
106
|
|
|
54
|
-
The main interface
|
|
107
|
+
The main interface for standard HTTP REST operations:
|
|
55
108
|
|
|
56
109
|
```typescript
|
|
57
110
|
interface RestService {
|
|
58
111
|
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
59
112
|
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
60
113
|
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
114
|
+
patch(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
61
115
|
del(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### FileService Interface
|
|
120
|
+
|
|
121
|
+
Dedicated interface for file upload and download operations:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface FileService {
|
|
62
125
|
upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
|
|
63
126
|
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
|
|
64
127
|
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
|
|
65
128
|
}
|
|
66
129
|
```
|
|
67
130
|
|
|
68
|
-
### Methods
|
|
131
|
+
### RestService Methods
|
|
69
132
|
|
|
70
133
|
#### `get(url, params?, dataProcessor?)`
|
|
134
|
+
Performs HTTP GET request to retrieve a resource.
|
|
71
135
|
- **url**: The endpoint URL
|
|
72
136
|
- **params**: Query parameters (optional)
|
|
73
137
|
- **dataProcessor**: Function to process response data (optional)
|
|
74
138
|
|
|
75
139
|
#### `post(url, data?, options?)`
|
|
140
|
+
Performs HTTP POST request to create a new resource.
|
|
76
141
|
- **url**: The endpoint URL
|
|
77
142
|
- **data**: Request payload (optional)
|
|
78
143
|
- **options**: Optional configuration object containing:
|
|
@@ -81,20 +146,36 @@ interface RestService {
|
|
|
81
146
|
- **dataProcessor**: Function to process response data (optional)
|
|
82
147
|
|
|
83
148
|
#### `put(url, data?, options?)`
|
|
84
|
-
|
|
149
|
+
Performs HTTP PUT request to update an entire resource.
|
|
150
|
+
- **url**: The endpoint URL
|
|
151
|
+
- **data**: Request payload (optional)
|
|
152
|
+
- **options**: Optional configuration object containing:
|
|
153
|
+
- **params**: Query parameters (optional)
|
|
154
|
+
- **contentType**: Content-Type header (optional, defaults to application/json)
|
|
155
|
+
- **dataProcessor**: Function to process response data (optional)
|
|
156
|
+
|
|
157
|
+
#### `patch(url, data?, options?)`
|
|
158
|
+
Performs HTTP PATCH request to partially update a resource.
|
|
159
|
+
- **url**: The endpoint URL
|
|
160
|
+
- **data**: Request payload with fields to update (optional)
|
|
85
161
|
- **options**: Optional configuration object containing:
|
|
86
162
|
- **params**: Query parameters (optional)
|
|
87
163
|
- **contentType**: Content-Type header (optional, defaults to application/json)
|
|
88
164
|
- **dataProcessor**: Function to process response data (optional)
|
|
89
165
|
|
|
90
166
|
#### `del(url, data?, options?)`
|
|
91
|
-
|
|
167
|
+
Performs HTTP DELETE request to delete a resource.
|
|
168
|
+
- **url**: The endpoint URL
|
|
169
|
+
- **data**: Request body data (optional)
|
|
92
170
|
- **options**: Optional configuration object containing:
|
|
93
171
|
- **params**: Query parameters (optional)
|
|
94
172
|
- **contentType**: Content-Type header (optional, defaults to application/json)
|
|
95
173
|
- **dataProcessor**: Function to process response data (optional)
|
|
96
174
|
|
|
175
|
+
### FileService Methods
|
|
176
|
+
|
|
97
177
|
#### `upload(url, params, file, fileKey?, dataProcessor?)`
|
|
178
|
+
Performs synchronous file upload operation.
|
|
98
179
|
- **url**: The upload endpoint URL
|
|
99
180
|
- **params**: Additional parameters for the upload request
|
|
100
181
|
- **file**: The File object to upload
|
|
@@ -102,6 +183,7 @@ For delete operations with optional request body.
|
|
|
102
183
|
- **dataProcessor**: Function to process response data (optional)
|
|
103
184
|
|
|
104
185
|
#### `asyncUpload(url, params, file, callback, fileKey?)`
|
|
186
|
+
Performs asynchronous file upload with progress monitoring and cancellation support.
|
|
105
187
|
- **url**: The upload endpoint URL
|
|
106
188
|
- **params**: Additional parameters for the upload request
|
|
107
189
|
- **file**: The File object to upload
|
|
@@ -110,6 +192,7 @@ For delete operations with optional request body.
|
|
|
110
192
|
- **Returns**: Promise that resolves to UploadProgress object for cancellation
|
|
111
193
|
|
|
112
194
|
#### `download(url, filename, params, method?, formData?)`
|
|
195
|
+
Performs file download operation.
|
|
113
196
|
- **url**: The download endpoint URL
|
|
114
197
|
- **filename**: The name to save the downloaded file
|
|
115
198
|
- **params**: Download request parameters
|
|
@@ -202,13 +285,16 @@ await api.post('/upload', data, {}, { contentType: TYPE_JSON });
|
|
|
202
285
|
|
|
203
286
|
Here's a complete example implementation using the native fetch API:
|
|
204
287
|
|
|
288
|
+
### RestService Implementation
|
|
289
|
+
|
|
205
290
|
```typescript
|
|
206
291
|
import RestService, {
|
|
207
292
|
ApiError,
|
|
208
293
|
PreInterceptor,
|
|
209
294
|
PostInterceptor,
|
|
210
295
|
RestfulOptions,
|
|
211
|
-
TYPE_JSON
|
|
296
|
+
TYPE_JSON,
|
|
297
|
+
DataProcessor
|
|
212
298
|
} from '@ticatec/restful_service_api';
|
|
213
299
|
|
|
214
300
|
class FetchRestService implements RestService {
|
|
@@ -241,6 +327,13 @@ class FetchRestService implements RestService {
|
|
|
241
327
|
return this.request('PUT', url + queryString, data, contentType, options?.dataProcessor);
|
|
242
328
|
}
|
|
243
329
|
|
|
330
|
+
async patch(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
331
|
+
const contentType = options?.contentType || TYPE_JSON;
|
|
332
|
+
const params = options?.params;
|
|
333
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
334
|
+
return this.request('PATCH', url + queryString, data, contentType, options?.dataProcessor);
|
|
335
|
+
}
|
|
336
|
+
|
|
244
337
|
async del(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
245
338
|
const contentType = options?.contentType || TYPE_JSON;
|
|
246
339
|
const params = options?.params;
|
|
@@ -298,60 +391,140 @@ class FetchRestService implements RestService {
|
|
|
298
391
|
const api = new FetchRestService('https://api.example.com');
|
|
299
392
|
const users = await api.get('/users');
|
|
300
393
|
const newUser = await api.post('/users', { name: 'John Doe' });
|
|
301
|
-
const
|
|
394
|
+
const partialUpdate = await api.patch('/users/1', { status: 'active' });
|
|
395
|
+
const fullUpdate = await api.put('/users/1', { name: 'Jane Doe', age: 30 });
|
|
302
396
|
```
|
|
303
397
|
|
|
304
|
-
###
|
|
398
|
+
### FileService Implementation
|
|
305
399
|
|
|
306
400
|
```typescript
|
|
307
|
-
import
|
|
308
|
-
UploadCallback,
|
|
309
|
-
UploadProgress
|
|
310
|
-
} from '@ticatec/restful_service_api';
|
|
401
|
+
import FileService, { UploadCallback, UploadProgress, DataProcessor } from '@ticatec/restful_service_api';
|
|
311
402
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const file = fileInput.files[0];
|
|
403
|
+
class FetchFileService implements FileService {
|
|
404
|
+
private baseURL: string;
|
|
315
405
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
} catch (error) {
|
|
320
|
-
console.error('Upload failed:', error);
|
|
321
|
-
}
|
|
406
|
+
constructor(baseURL: string) {
|
|
407
|
+
this.baseURL = baseURL;
|
|
408
|
+
}
|
|
322
409
|
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
410
|
+
async upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any> {
|
|
411
|
+
const formData = new FormData();
|
|
412
|
+
formData.append(fileKey || 'file', file);
|
|
413
|
+
|
|
414
|
+
// Add additional parameters
|
|
415
|
+
Object.keys(params).forEach(key => {
|
|
416
|
+
formData.append(key, params[key]);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
const response = await fetch(this.baseURL + url, {
|
|
420
|
+
method: 'POST',
|
|
421
|
+
body: formData
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
if (!response.ok) {
|
|
425
|
+
throw new Error(`Upload failed: ${response.statusText}`);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const data = await response.json();
|
|
429
|
+
return dataProcessor ? dataProcessor(data) : data;
|
|
334
430
|
}
|
|
335
|
-
};
|
|
336
431
|
|
|
337
|
-
|
|
432
|
+
async asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress> {
|
|
433
|
+
const formData = new FormData();
|
|
434
|
+
formData.append(fileKey || 'file', file);
|
|
338
435
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}, 5000);
|
|
436
|
+
Object.keys(params).forEach(key => {
|
|
437
|
+
formData.append(key, params[key]);
|
|
438
|
+
});
|
|
343
439
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
440
|
+
const xhr = new XMLHttpRequest();
|
|
441
|
+
|
|
442
|
+
return new Promise((resolve) => {
|
|
443
|
+
xhr.upload.addEventListener('progress', (e) => {
|
|
444
|
+
if (e.lengthComputable && callback.progressUpdate) {
|
|
445
|
+
callback.progressUpdate(e.loaded);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
xhr.addEventListener('load', () => {
|
|
450
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
451
|
+
const data = JSON.parse(xhr.responseText);
|
|
452
|
+
callback.onCompleted(data);
|
|
453
|
+
} else if (callback.handleError) {
|
|
454
|
+
callback.handleError(new Error(`Upload failed: ${xhr.statusText}`));
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
xhr.addEventListener('error', () => {
|
|
459
|
+
if (callback.handleError) {
|
|
460
|
+
callback.handleError(new Error('Network error'));
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
xhr.open(callback.method || 'POST', this.baseURL + url);
|
|
465
|
+
xhr.send(formData);
|
|
466
|
+
|
|
467
|
+
resolve({
|
|
468
|
+
cancel: () => xhr.abort()
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any> {
|
|
474
|
+
let fullUrl = this.baseURL + url;
|
|
475
|
+
|
|
476
|
+
if (method === 'POST' && formData) {
|
|
477
|
+
const form = new FormData();
|
|
478
|
+
Object.keys(formData).forEach(key => {
|
|
479
|
+
form.append(key, formData[key]);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const response = await fetch(fullUrl, {
|
|
483
|
+
method: 'POST',
|
|
484
|
+
body: form
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
const blob = await response.blob();
|
|
488
|
+
const downloadUrl = window.URL.createObjectURL(blob);
|
|
489
|
+
const a = document.createElement('a');
|
|
490
|
+
a.href = downloadUrl;
|
|
491
|
+
a.download = filename;
|
|
492
|
+
a.click();
|
|
493
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
494
|
+
} else {
|
|
495
|
+
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
496
|
+
fullUrl += queryString;
|
|
497
|
+
|
|
498
|
+
const response = await fetch(fullUrl);
|
|
499
|
+
const blob = await response.blob();
|
|
500
|
+
const downloadUrl = window.URL.createObjectURL(blob);
|
|
501
|
+
const a = document.createElement('a');
|
|
502
|
+
a.href = downloadUrl;
|
|
503
|
+
a.download = filename;
|
|
504
|
+
a.click();
|
|
505
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
350
508
|
}
|
|
351
509
|
|
|
352
|
-
//
|
|
353
|
-
const
|
|
354
|
-
|
|
510
|
+
// Usage
|
|
511
|
+
const fileApi = new FetchFileService('https://api.example.com');
|
|
512
|
+
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
|
513
|
+
const file = fileInput.files[0];
|
|
514
|
+
|
|
515
|
+
// Simple upload
|
|
516
|
+
const result = await fileApi.upload('/upload', { userId: 123 }, file);
|
|
517
|
+
|
|
518
|
+
// Async upload with progress
|
|
519
|
+
const progress = await fileApi.asyncUpload('/upload', { userId: 123 }, file, {
|
|
520
|
+
method: 'POST',
|
|
521
|
+
progressUpdate: (loaded) => console.log(`Uploaded: ${loaded} bytes`),
|
|
522
|
+
onCompleted: (data) => console.log('Done!', data),
|
|
523
|
+
handleError: (err) => console.error('Error!', err)
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// Download file
|
|
527
|
+
await fileApi.download('/files/document.pdf', 'my-document.pdf', { userId: 123 });
|
|
355
528
|
```
|
|
356
529
|
|
|
357
530
|
## Utility Functions
|
package/dist/ApiError.d.ts
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API error class for handling HTTP request errors
|
|
3
|
+
*/
|
|
1
4
|
export default class ApiError extends Error {
|
|
2
5
|
private _code;
|
|
3
6
|
private _details;
|
|
4
7
|
private _status;
|
|
8
|
+
/**
|
|
9
|
+
* Error code from the API response
|
|
10
|
+
*/
|
|
5
11
|
get code(): any;
|
|
12
|
+
/**
|
|
13
|
+
* Detailed error information from the API response
|
|
14
|
+
*/
|
|
6
15
|
get details(): any;
|
|
16
|
+
/**
|
|
17
|
+
* HTTP status code of the error response
|
|
18
|
+
*/
|
|
7
19
|
get status(): any;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new API error instance
|
|
22
|
+
* @param status HTTP status code
|
|
23
|
+
* @param err Error object containing code and details
|
|
24
|
+
*/
|
|
8
25
|
constructor(status: any, err: any);
|
|
9
26
|
}
|
package/dist/ApiError.js
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API error class for handling HTTP request errors
|
|
3
|
+
*/
|
|
1
4
|
export default class ApiError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* Error code from the API response
|
|
7
|
+
*/
|
|
2
8
|
get code() {
|
|
3
9
|
return this._code;
|
|
4
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Detailed error information from the API response
|
|
13
|
+
*/
|
|
5
14
|
get details() {
|
|
6
15
|
return this._details;
|
|
7
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* HTTP status code of the error response
|
|
19
|
+
*/
|
|
8
20
|
get status() {
|
|
9
21
|
return this._status;
|
|
10
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new API error instance
|
|
25
|
+
* @param status HTTP status code
|
|
26
|
+
* @param err Error object containing code and details
|
|
27
|
+
*/
|
|
11
28
|
constructor(status, err) {
|
|
12
29
|
super(err.code);
|
|
13
30
|
this.name = this.constructor.name;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import UploadCallback from "./UploadCallback";
|
|
2
|
+
import { DataProcessor } from "./RestService";
|
|
3
|
+
/**
|
|
4
|
+
* File service interface for file upload and download operations
|
|
5
|
+
*/
|
|
6
|
+
export default interface FileService {
|
|
7
|
+
/**
|
|
8
|
+
* Performs synchronous file upload operation
|
|
9
|
+
* @param url The target URL path for upload
|
|
10
|
+
* @param params Parameters object for the upload request
|
|
11
|
+
* @param file The file object to upload
|
|
12
|
+
* @param fileKey Optional file field name, defaults to 'file'
|
|
13
|
+
* @param dataProcessor Optional data processing function to transform response data before returning
|
|
14
|
+
* @returns Promise that resolves to the server response data
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Simple file upload
|
|
19
|
+
* const file = document.querySelector('input[type="file"]').files[0];
|
|
20
|
+
* const result = await fileService.upload('/api/upload', { userId: 123 }, file);
|
|
21
|
+
*
|
|
22
|
+
* // Upload with custom file key
|
|
23
|
+
* const result = await fileService.upload('/api/upload', {}, file, 'avatar');
|
|
24
|
+
*
|
|
25
|
+
* // Upload with data processor
|
|
26
|
+
* const result = await fileService.upload('/api/upload', {}, file, 'file', (data) => data.url);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
|
|
30
|
+
/**
|
|
31
|
+
* Performs asynchronous file upload operation with progress monitoring and cancellation support
|
|
32
|
+
* @param url The target URL path for upload
|
|
33
|
+
* @param params Parameters object for the upload request
|
|
34
|
+
* @param file The file object to upload
|
|
35
|
+
* @param callback Callback function during upload process, including progress updates, error handling, etc.
|
|
36
|
+
* @param fileKey Optional file field name, defaults to 'file'
|
|
37
|
+
* @returns Promise that resolves to UploadProgress object, which can be used to cancel the upload
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Async upload with progress monitoring
|
|
42
|
+
* const progress = await fileService.asyncUpload(
|
|
43
|
+
* '/api/upload',
|
|
44
|
+
* { userId: 123 },
|
|
45
|
+
* file,
|
|
46
|
+
* {
|
|
47
|
+
* onProgress: (loaded, total, percent) => {
|
|
48
|
+
* console.log(`Upload: ${percent}%`);
|
|
49
|
+
* },
|
|
50
|
+
* onCompleted: (data) => {
|
|
51
|
+
* console.log('Upload complete:', data);
|
|
52
|
+
* },
|
|
53
|
+
* onError: (error) => {
|
|
54
|
+
* console.error('Upload failed:', error);
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* );
|
|
58
|
+
*
|
|
59
|
+
* // Cancel the upload
|
|
60
|
+
* progress.abort();
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<import("./UploadCallback").UploadProgress>;
|
|
64
|
+
/**
|
|
65
|
+
* Performs file download operation
|
|
66
|
+
* @param url The URL path to download the file
|
|
67
|
+
* @param filename The filename to save as
|
|
68
|
+
* @param params Parameters object for the download request
|
|
69
|
+
* @param method Optional HTTP method, defaults to GET
|
|
70
|
+
* @param formData Optional form data for POST download
|
|
71
|
+
* @returns Promise that resolves to the download result
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* // Simple file download
|
|
76
|
+
* await fileService.download('/api/files/123', 'document.pdf', {});
|
|
77
|
+
*
|
|
78
|
+
* // Download with parameters
|
|
79
|
+
* await fileService.download('/api/files/export', 'report.xlsx', {
|
|
80
|
+
* format: 'xlsx',
|
|
81
|
+
* date: '2024-01-01'
|
|
82
|
+
* });
|
|
83
|
+
*
|
|
84
|
+
* // Download via POST
|
|
85
|
+
* await fileService.download('/api/files/generate', 'custom.pdf', {}, 'POST', {
|
|
86
|
+
* template: 'invoice',
|
|
87
|
+
* data: invoiceData
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
|
|
92
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/RestService.d.ts
CHANGED
|
@@ -1,97 +1,171 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Result object returned by pre-interceptor
|
|
3
|
+
*/
|
|
2
4
|
export interface PreInterceptorResult {
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* Additional headers to add to the request
|
|
5
7
|
*/
|
|
6
8
|
headers: any;
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* Request timeout in milliseconds
|
|
9
11
|
*/
|
|
10
12
|
timeout?: number;
|
|
11
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Data processor function type for transforming response data
|
|
16
|
+
*/
|
|
12
17
|
export type DataProcessor = (data: any) => any;
|
|
18
|
+
/**
|
|
19
|
+
* Pre-interceptor function type for modifying requests before sending
|
|
20
|
+
* @param method HTTP method (GET, POST, etc.)
|
|
21
|
+
* @param url Request URL
|
|
22
|
+
* @returns PreInterceptorResult object with optional headers and timeout
|
|
23
|
+
*/
|
|
13
24
|
export type PreInterceptor = (method: string, url: string) => PreInterceptorResult;
|
|
25
|
+
/**
|
|
26
|
+
* Post-interceptor function type for processing responses after receiving
|
|
27
|
+
* @param data Response data from the server
|
|
28
|
+
* @returns Promise that resolves to processed data
|
|
29
|
+
*/
|
|
14
30
|
export type PostInterceptor = (data: any) => Promise<any>;
|
|
31
|
+
/**
|
|
32
|
+
* Error handler function type for handling request errors
|
|
33
|
+
* @param ex The error object
|
|
34
|
+
* @returns Boolean indicating if the error was handled (true) or should be thrown (false)
|
|
35
|
+
*/
|
|
15
36
|
export type ErrorHandler = (ex: Error) => boolean;
|
|
37
|
+
/**
|
|
38
|
+
* RESTful API request options
|
|
39
|
+
*/
|
|
16
40
|
export type RestfulOptions = {
|
|
17
41
|
/**
|
|
18
|
-
*
|
|
42
|
+
* Optional Content-Type header, defaults to 'application/json'
|
|
19
43
|
*/
|
|
20
44
|
contentType?: string;
|
|
21
45
|
/**
|
|
22
|
-
*
|
|
46
|
+
* Optional data processing function to transform response data before returning
|
|
23
47
|
*/
|
|
24
48
|
dataProcessor?: DataProcessor;
|
|
25
49
|
/**
|
|
26
|
-
*
|
|
50
|
+
* Optional query parameters object that will be converted to URL query string
|
|
27
51
|
*/
|
|
28
52
|
params?: any;
|
|
29
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* HTTP header name for Content-Type
|
|
56
|
+
*/
|
|
30
57
|
export declare const CONTENT_TYPE_NAME = "Content-Type";
|
|
58
|
+
/**
|
|
59
|
+
* MIME type for JSON content
|
|
60
|
+
*/
|
|
31
61
|
export declare const TYPE_JSON = "application/json";
|
|
62
|
+
/**
|
|
63
|
+
* MIME type for HTML content
|
|
64
|
+
*/
|
|
32
65
|
export declare const TYPE_HTML = "text/html";
|
|
66
|
+
/**
|
|
67
|
+
* MIME type for plain text content
|
|
68
|
+
*/
|
|
33
69
|
export declare const TYPE_TEXT = "text/plain";
|
|
70
|
+
/**
|
|
71
|
+
* RESTful API service interface for standard HTTP operations
|
|
72
|
+
*/
|
|
34
73
|
export default interface RestService {
|
|
35
74
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @param url
|
|
38
|
-
* @param params
|
|
39
|
-
* @param dataProcessor
|
|
40
|
-
* @returns
|
|
75
|
+
* Performs an HTTP GET request to retrieve a resource
|
|
76
|
+
* @param url The target URL path for the request
|
|
77
|
+
* @param params Query parameters object that will be converted to URL query string
|
|
78
|
+
* @param dataProcessor Optional data processing function to transform response data before returning
|
|
79
|
+
* @returns Promise that resolves to the server response data
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* // Simple GET request
|
|
84
|
+
* const users = await restService.get('/api/users');
|
|
85
|
+
*
|
|
86
|
+
* // GET with query parameters
|
|
87
|
+
* const filteredUsers = await restService.get('/api/users', { page: 1, limit: 10 });
|
|
88
|
+
*
|
|
89
|
+
* // GET with data processor
|
|
90
|
+
* const users = await restService.get('/api/users', null, (data) => data.items);
|
|
91
|
+
* ```
|
|
41
92
|
*/
|
|
42
93
|
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
43
94
|
/**
|
|
44
|
-
*
|
|
45
|
-
* @param url
|
|
46
|
-
* @param data
|
|
47
|
-
* @param options
|
|
48
|
-
* @returns
|
|
95
|
+
* Performs an HTTP POST request to create a new resource
|
|
96
|
+
* @param url The target URL path for the request
|
|
97
|
+
* @param data Request body data to be sent, typically an object or string
|
|
98
|
+
* @param options Optional request configuration options, including contentType and dataProcessor
|
|
99
|
+
* @returns Promise that resolves to the server response data
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* // Simple POST request
|
|
104
|
+
* const newUser = await restService.post('/api/users', { name: 'John', age: 30 });
|
|
105
|
+
*
|
|
106
|
+
* // POST with custom content type
|
|
107
|
+
* const result = await restService.post('/api/data', formData, {
|
|
108
|
+
* contentType: 'multipart/form-data'
|
|
109
|
+
* });
|
|
110
|
+
*
|
|
111
|
+
* // POST with data processor
|
|
112
|
+
* const user = await restService.post('/api/users', userData, {
|
|
113
|
+
* dataProcessor: (data) => data.result
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
49
116
|
*/
|
|
50
117
|
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
51
118
|
/**
|
|
52
|
-
*
|
|
53
|
-
* @param url
|
|
54
|
-
* @param data
|
|
55
|
-
* @param options
|
|
56
|
-
* @returns
|
|
119
|
+
* Performs an HTTP PUT request to update an existing resource
|
|
120
|
+
* @param url The target URL path for the request
|
|
121
|
+
* @param data Optional request body data to be sent for updating the resource
|
|
122
|
+
* @param options Optional request configuration options, including contentType and dataProcessor
|
|
123
|
+
* @returns Promise that resolves to the server response data
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* // Update a user
|
|
128
|
+
* const updatedUser = await restService.put('/api/users/123', { name: 'John Doe' });
|
|
129
|
+
*
|
|
130
|
+
* // PUT without data (some APIs may support this)
|
|
131
|
+
* const result = await restService.put('/api/users/123/toggle-status');
|
|
132
|
+
* ```
|
|
57
133
|
*/
|
|
58
134
|
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
59
135
|
/**
|
|
60
|
-
*
|
|
61
|
-
* @param url
|
|
62
|
-
* @param data
|
|
63
|
-
* @param options
|
|
64
|
-
* @returns
|
|
136
|
+
* Performs an HTTP DELETE request to delete a resource
|
|
137
|
+
* @param url The target URL path for the request
|
|
138
|
+
* @param data Optional request body data, some DELETE operations may require sending data
|
|
139
|
+
* @param options Optional request configuration options, including contentType and dataProcessor
|
|
140
|
+
* @returns Promise that resolves to the server response data
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* // Delete a user
|
|
145
|
+
* await restService.del('/api/users/123');
|
|
146
|
+
*
|
|
147
|
+
* // DELETE with request body
|
|
148
|
+
* await restService.del('/api/users/batch', { ids: [1, 2, 3] });
|
|
149
|
+
* ```
|
|
65
150
|
*/
|
|
66
151
|
del(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
67
152
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @param url
|
|
70
|
-
* @param
|
|
71
|
-
* @param
|
|
72
|
-
* @
|
|
73
|
-
*
|
|
74
|
-
* @
|
|
153
|
+
* Performs an HTTP PATCH request to partially update a resource
|
|
154
|
+
* @param url The target URL path for the request
|
|
155
|
+
* @param data Optional request body data to be sent for partially updating the resource
|
|
156
|
+
* @param options Optional request configuration options, including contentType and dataProcessor
|
|
157
|
+
* @returns Promise that resolves to the server response data
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // Partially update a user
|
|
162
|
+
* const updatedUser = await restService.patch('/api/users/123', { status: 'active' });
|
|
163
|
+
*
|
|
164
|
+
* // PATCH with options
|
|
165
|
+
* const result = await restService.patch('/api/users/123', { age: 31 }, {
|
|
166
|
+
* dataProcessor: (data) => data.user
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
75
169
|
*/
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* 执行异步文件上传操作,支持进度监控和取消功能
|
|
79
|
-
* @param url 上传的目标URL路径
|
|
80
|
-
* @param params 上传请求的参数对象
|
|
81
|
-
* @param file 要上传的文件对象
|
|
82
|
-
* @param callback 上传过程中的回调函数,包含进度更新、错误处理等
|
|
83
|
-
* @param fileKey 可选的文件字段名,默认为'file'
|
|
84
|
-
* @returns 返回Promise,解析为UploadProgress对象,可用于取消上传
|
|
85
|
-
*/
|
|
86
|
-
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
|
|
87
|
-
/**
|
|
88
|
-
* 执行文件下载操作
|
|
89
|
-
* @param url 下载文件的URL路径
|
|
90
|
-
* @param filename 保存的文件名
|
|
91
|
-
* @param params 下载请求的参数对象
|
|
92
|
-
* @param method 可选的HTTP方法,默认为GET
|
|
93
|
-
* @param formData 可选的表单数据,用于POST下载
|
|
94
|
-
* @returns 返回Promise,解析为下载结果
|
|
95
|
-
*/
|
|
96
|
-
download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
|
|
170
|
+
patch(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
97
171
|
}
|
package/dist/RestService.js
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP header name for Content-Type
|
|
3
|
+
*/
|
|
1
4
|
export const CONTENT_TYPE_NAME = 'Content-Type';
|
|
5
|
+
/**
|
|
6
|
+
* MIME type for JSON content
|
|
7
|
+
*/
|
|
2
8
|
export const TYPE_JSON = "application/json";
|
|
9
|
+
/**
|
|
10
|
+
* MIME type for HTML content
|
|
11
|
+
*/
|
|
3
12
|
export const TYPE_HTML = "text/html";
|
|
13
|
+
/**
|
|
14
|
+
* MIME type for plain text content
|
|
15
|
+
*/
|
|
4
16
|
export const TYPE_TEXT = "text/plain";
|
package/dist/UploadCallback.d.ts
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @param uploadBytes
|
|
2
|
+
* Upload progress update callback function type
|
|
3
|
+
* @param uploadBytes Number of bytes uploaded
|
|
4
4
|
*/
|
|
5
5
|
export type ProgressUpdate = (uploadBytes: number) => void;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
* @param e
|
|
7
|
+
* Upload error handling callback function type
|
|
8
|
+
* @param e Error object that occurred during upload
|
|
9
9
|
*/
|
|
10
10
|
export type ErrorHandler = (e: Error) => void;
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @param data
|
|
12
|
+
* Upload completion callback function type
|
|
13
|
+
* @param data Response data returned from the server
|
|
14
14
|
*/
|
|
15
15
|
export type OnCompleted = (data: any) => void;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Upload progress control interface, providing control functions during upload process
|
|
18
18
|
*/
|
|
19
19
|
export interface UploadProgress {
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* Cancel the ongoing upload operation
|
|
22
22
|
*/
|
|
23
23
|
cancel: () => void;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @param url
|
|
28
|
-
* @param thumbnail
|
|
26
|
+
* Callback function type after file upload completion
|
|
27
|
+
* @param url File access URL after upload
|
|
28
|
+
* @param thumbnail Optional thumbnail URL
|
|
29
29
|
*/
|
|
30
30
|
export type OnUploaded = (url: string, thumbnail?: string) => void;
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* File upload callback interface, defining various callback functions during upload process
|
|
33
33
|
*/
|
|
34
34
|
export default interface UploadCallback {
|
|
35
35
|
/**
|
|
36
|
-
* HTTP
|
|
36
|
+
* HTTP request method, defaults to POST, but allows PUT or other methods in special cases
|
|
37
37
|
*/
|
|
38
38
|
method: string;
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* Optional upload progress update callback function
|
|
41
41
|
*/
|
|
42
42
|
progressUpdate?: ProgressUpdate;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* Optional error handling callback function
|
|
45
45
|
*/
|
|
46
46
|
handleError?: ErrorHandler;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
48
|
+
* Required upload completion callback function
|
|
49
49
|
*/
|
|
50
50
|
onCompleted: OnCompleted;
|
|
51
51
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ApiError from "./ApiError";
|
|
2
2
|
import RestService from "./RestService";
|
|
3
|
+
import FileService from "./FileService";
|
|
3
4
|
import { ErrorHandler, PostInterceptor, PreInterceptor, DataProcessor } from "./RestService";
|
|
4
5
|
import { PreInterceptorResult } from "./RestService";
|
|
5
6
|
import { CONTENT_TYPE_NAME, TYPE_JSON, TYPE_HTML, TYPE_TEXT } from "./RestService";
|
|
@@ -7,6 +8,8 @@ import UploadCallback, { UploadProgress, ProgressUpdate, OnCompleted, OnUploaded
|
|
|
7
8
|
import { RestfulOptions } from "./RestService";
|
|
8
9
|
export default RestService;
|
|
9
10
|
export { ApiError };
|
|
11
|
+
export { RestService };
|
|
12
|
+
export { FileService };
|
|
10
13
|
export type { ErrorHandler, PostInterceptor, PreInterceptor, DataProcessor };
|
|
11
14
|
export type { PreInterceptorResult };
|
|
12
15
|
export { CONTENT_TYPE_NAME, TYPE_JSON, TYPE_HTML, TYPE_TEXT };
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
"type": "module",
|
|
2
3
|
"name": "@ticatec/restful_service_api",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A lightweight TypeScript RESTful API client for browsers with error handling.",
|
|
4
|
+
"version": "0.5.0",
|
|
5
|
+
"description": "A lightweight TypeScript RESTful API client for browsers with error handling. (ESM only, v0.5.0+)",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"module": "dist/index.js",
|
|
7
8
|
"types": "dist/index.d.ts",
|