@ticatec/restful_service_api 0.6.0 → 0.7.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 +73 -22
- package/README.md +74 -22
- package/dist/FileService.d.ts +7 -7
- package/dist/RestService.d.ts +20 -13
- package/dist/UploadCallback.d.ts +1 -1
- package/dist/index.d.ts +8 -9
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README-CN.md
CHANGED
|
@@ -18,6 +18,32 @@
|
|
|
18
18
|
- 🌐 **浏览器优先**: 专为前端应用程序设计
|
|
19
19
|
- ✨ **PATCH 支持**: 完整支持 HTTP PATCH 方法进行部分更新
|
|
20
20
|
|
|
21
|
+
## ⚠️ v0.7.0 重大变更
|
|
22
|
+
|
|
23
|
+
**`RestfulOptions.contentType` 已被移除,改为使用通用的 `headers` 字段。**
|
|
24
|
+
|
|
25
|
+
### 对您的影响
|
|
26
|
+
|
|
27
|
+
- `RestfulOptions`(用于 `post`/`put`/`del`/`patch`)不再识别 `contentType` 字段,
|
|
28
|
+
请把 `{ contentType: 'multipart/form-data' }` 改为
|
|
29
|
+
`{ headers: { 'Content-Type': 'multipart/form-data' } }`。
|
|
30
|
+
- `get()` 新增了一个可选的第 4 个参数:`get(url, params?, dataProcessor?, headers?)`。
|
|
31
|
+
已有的按位置调用方式(`get(url)`、`get(url, params)`、`get(url, params, dataProcessor)`)不受影响。
|
|
32
|
+
- 这也让单次请求携带任意自定义请求头成为可能(不仅限于 Content-Type),例如通过
|
|
33
|
+
`If-None-Match` 实现条件 GET —— 参见"自定义请求头(例如条件请求)"一节。
|
|
34
|
+
|
|
35
|
+
### 迁移指南
|
|
36
|
+
|
|
37
|
+
**之前(v0.6.x 及更早版本):**
|
|
38
|
+
```typescript
|
|
39
|
+
await api.post('/upload', formData, { contentType: 'multipart/form-data' });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**之后(v0.7.0+):**
|
|
43
|
+
```typescript
|
|
44
|
+
await api.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } });
|
|
45
|
+
```
|
|
46
|
+
|
|
21
47
|
## ⚠️ v0.5.0 重大变更
|
|
22
48
|
|
|
23
49
|
**从 0.5.0 版本开始,此包已迁移到 ESM (ECMAScript Modules) 格式。**
|
|
@@ -59,7 +85,7 @@ import RestService, { FileService } from '@ticatec/restful_service_api';
|
|
|
59
85
|
|
|
60
86
|
// 实现 RestService 接口
|
|
61
87
|
class MyApiClient implements RestService {
|
|
62
|
-
async get(url: string, params?: any, dataProcessor?: DataProcessor) {
|
|
88
|
+
async get(url: string, params?: any, dataProcessor?: DataProcessor, headers?: Record<string, string>) {
|
|
63
89
|
// 在这里实现
|
|
64
90
|
}
|
|
65
91
|
|
|
@@ -109,7 +135,7 @@ const result = await fileApi.upload('/upload', { userId: 123 }, file);
|
|
|
109
135
|
|
|
110
136
|
```typescript
|
|
111
137
|
interface RestService {
|
|
112
|
-
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
138
|
+
get(url: string, params?: any, dataProcessor?: DataProcessor, headers?: Record<string, string>): Promise<any>;
|
|
113
139
|
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
114
140
|
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
115
141
|
patch(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
@@ -131,11 +157,12 @@ interface FileService {
|
|
|
131
157
|
|
|
132
158
|
### RestService 方法
|
|
133
159
|
|
|
134
|
-
#### `get(url, params?, dataProcessor?)`
|
|
160
|
+
#### `get(url, params?, dataProcessor?, headers?)`
|
|
135
161
|
执行 HTTP GET 请求获取资源。
|
|
136
162
|
- **url**: 接口端点 URL
|
|
137
163
|
- **params**: 查询参数(可选)
|
|
138
164
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
165
|
+
- **headers**: 本次调用的自定义请求头(可选),例如条件请求:`{ 'If-None-Match': contentHash }`
|
|
139
166
|
|
|
140
167
|
#### `post(url, data?, options?)`
|
|
141
168
|
执行 HTTP POST 请求创建新资源。
|
|
@@ -143,7 +170,8 @@ interface FileService {
|
|
|
143
170
|
- **data**: 请求载荷(可选)
|
|
144
171
|
- **options**: 可选的配置对象,包含:
|
|
145
172
|
- **params**: 查询参数(可选)
|
|
146
|
-
- **
|
|
173
|
+
- **headers**: 本次调用的自定义请求头(可选)。可用于覆盖默认的 `Content-Type`
|
|
174
|
+
(`application/json`),例如 `{ 'Content-Type': 'multipart/form-data' }`
|
|
147
175
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
148
176
|
|
|
149
177
|
#### `put(url, data?, options?)`
|
|
@@ -152,7 +180,7 @@ interface FileService {
|
|
|
152
180
|
- **data**: 请求载荷(可选)
|
|
153
181
|
- **options**: 可选的配置对象,包含:
|
|
154
182
|
- **params**: 查询参数(可选)
|
|
155
|
-
- **
|
|
183
|
+
- **headers**: 本次调用的自定义请求头(可选)
|
|
156
184
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
157
185
|
|
|
158
186
|
#### `patch(url, data?, options?)`
|
|
@@ -161,7 +189,7 @@ interface FileService {
|
|
|
161
189
|
- **data**: 包含要更新字段的请求载荷(可选)
|
|
162
190
|
- **options**: 可选的配置对象,包含:
|
|
163
191
|
- **params**: 查询参数(可选)
|
|
164
|
-
- **
|
|
192
|
+
- **headers**: 本次调用的自定义请求头(可选)
|
|
165
193
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
166
194
|
|
|
167
195
|
#### `del(url, data?, options?)`
|
|
@@ -170,7 +198,7 @@ interface FileService {
|
|
|
170
198
|
- **data**: 请求体数据(可选)
|
|
171
199
|
- **options**: 可选的配置对象,包含:
|
|
172
200
|
- **params**: 查询参数(可选)
|
|
173
|
-
- **
|
|
201
|
+
- **headers**: 本次调用的自定义请求头(可选)
|
|
174
202
|
- **dataProcessor**: 处理响应数据的函数(可选)
|
|
175
203
|
|
|
176
204
|
### FileService 方法
|
|
@@ -232,7 +260,7 @@ import {
|
|
|
232
260
|
// RestfulOptions 用于配置请求
|
|
233
261
|
const options: RestfulOptions = {
|
|
234
262
|
params: { page: 1, limit: 10 },
|
|
235
|
-
|
|
263
|
+
headers: { 'Content-Type': 'application/json' },
|
|
236
264
|
dataProcessor: (data: any) => data.results || data
|
|
237
265
|
};
|
|
238
266
|
|
|
@@ -278,8 +306,34 @@ import {
|
|
|
278
306
|
TYPE_TEXT
|
|
279
307
|
} from '@ticatec/restful_service_api';
|
|
280
308
|
|
|
281
|
-
// 使用示例
|
|
282
|
-
await api.post('/upload', data, {
|
|
309
|
+
// 使用示例 - 通过 RestfulOptions.headers 显式设置请求头
|
|
310
|
+
await api.post('/upload', data, { headers: { [CONTENT_TYPE_NAME]: TYPE_JSON } });
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 自定义请求头(例如条件请求)
|
|
314
|
+
|
|
315
|
+
`RestfulOptions.headers`(以及 `get()` 的第 4 个参数 `headers`)允许为单次请求附加自定义请求头。
|
|
316
|
+
一个常见场景是基于本地缓存的 ETag/hash 发起条件 GET 请求:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// 第一次请求:还没有缓存的 hash
|
|
320
|
+
const pack = await api.get('/messages/node1');
|
|
321
|
+
localStorage.setItem('node1-hash', pack.contentHash);
|
|
322
|
+
|
|
323
|
+
// 之后:把缓存的 hash 作为 If-None-Match 发送
|
|
324
|
+
const cachedHash = localStorage.getItem('node1-hash');
|
|
325
|
+
try {
|
|
326
|
+
const updated = await api.get('/messages/node1', undefined, undefined, {
|
|
327
|
+
'If-None-Match': cachedHash ?? ''
|
|
328
|
+
});
|
|
329
|
+
// 服务端返回 200 —— 内容有变化,使用 `updated`
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (error instanceof ApiError && Number(error.status) === 304) {
|
|
332
|
+
// 服务端返回 304 Not Modified —— 本地缓存仍然有效
|
|
333
|
+
} else {
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
283
337
|
```
|
|
284
338
|
|
|
285
339
|
## 实现示例
|
|
@@ -309,48 +363,45 @@ class FetchRestService implements RestService {
|
|
|
309
363
|
this.postInterceptor = postInterceptor;
|
|
310
364
|
}
|
|
311
365
|
|
|
312
|
-
async get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any> {
|
|
366
|
+
async get(url: string, params?: any, dataProcessor?: DataProcessor, headers?: Record<string, string>): Promise<any> {
|
|
313
367
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
314
|
-
return this.request('GET', url + queryString, null,
|
|
368
|
+
return this.request('GET', url + queryString, null, headers, dataProcessor);
|
|
315
369
|
}
|
|
316
370
|
|
|
317
371
|
async post(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
318
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
319
372
|
const params = options?.params;
|
|
320
373
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
321
|
-
return this.request('POST', url + queryString, data,
|
|
374
|
+
return this.request('POST', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
322
375
|
}
|
|
323
376
|
|
|
324
377
|
async put(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
325
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
326
378
|
const params = options?.params;
|
|
327
379
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
328
|
-
return this.request('PUT', url + queryString, data,
|
|
380
|
+
return this.request('PUT', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
329
381
|
}
|
|
330
382
|
|
|
331
383
|
async patch(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
332
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
333
384
|
const params = options?.params;
|
|
334
385
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
335
|
-
return this.request('PATCH', url + queryString, data,
|
|
386
|
+
return this.request('PATCH', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
336
387
|
}
|
|
337
388
|
|
|
338
389
|
async del(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
339
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
340
390
|
const params = options?.params;
|
|
341
391
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
342
|
-
return this.request('DELETE', url + queryString, data,
|
|
392
|
+
return this.request('DELETE', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
343
393
|
}
|
|
344
394
|
|
|
345
|
-
private async request(method: string, url: string, body?: any,
|
|
395
|
+
private async request(method: string, url: string, body?: any, customHeaders?: Record<string, string>, dataProcessor?: DataProcessor): Promise<any> {
|
|
346
396
|
const fullUrl = this.baseURL + url;
|
|
347
397
|
|
|
348
398
|
// 应用请求前拦截器
|
|
349
399
|
const interceptorResult = this.preInterceptor?.(method, fullUrl) || { headers: {} };
|
|
350
400
|
|
|
351
401
|
const headers = {
|
|
402
|
+
'Content-Type': TYPE_JSON,
|
|
352
403
|
...interceptorResult.headers,
|
|
353
|
-
...
|
|
404
|
+
...customHeaders
|
|
354
405
|
};
|
|
355
406
|
|
|
356
407
|
try {
|
package/README.md
CHANGED
|
@@ -18,6 +18,31 @@ A lightweight TypeScript RESTful API client for browsers with comprehensive erro
|
|
|
18
18
|
- 🌐 **Browser-First**: Designed specifically for frontend applications
|
|
19
19
|
- ✨ **PATCH Support**: Full support for HTTP PATCH method for partial updates
|
|
20
20
|
|
|
21
|
+
## ⚠️ Breaking Changes in v0.7.0
|
|
22
|
+
|
|
23
|
+
**`RestfulOptions.contentType` has been removed in favor of a general-purpose `headers` field.**
|
|
24
|
+
|
|
25
|
+
### What This Means for You
|
|
26
|
+
|
|
27
|
+
- `contentType` is no longer a recognized field on `RestfulOptions` (used by `post`/`put`/`del`/`patch`).
|
|
28
|
+
Replace `{ contentType: 'multipart/form-data' }` with `{ headers: { 'Content-Type': 'multipart/form-data' } }`.
|
|
29
|
+
- `get()` gained a new, optional 4th parameter: `get(url, params?, dataProcessor?, headers?)`. Existing
|
|
30
|
+
positional calls (`get(url)`, `get(url, params)`, `get(url, params, dataProcessor)`) are unaffected.
|
|
31
|
+
- This also enables custom per-call headers in general (not just Content-Type), e.g. a conditional
|
|
32
|
+
GET via `If-None-Match` — see [Custom Headers (e.g. Conditional Requests)](#custom-headers-eg-conditional-requests).
|
|
33
|
+
|
|
34
|
+
### Migration Guide
|
|
35
|
+
|
|
36
|
+
**Before (v0.6.x and earlier):**
|
|
37
|
+
```typescript
|
|
38
|
+
await api.post('/upload', formData, { contentType: 'multipart/form-data' });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**After (v0.7.0+):**
|
|
42
|
+
```typescript
|
|
43
|
+
await api.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } });
|
|
44
|
+
```
|
|
45
|
+
|
|
21
46
|
## ⚠️ Breaking Changes in v0.5.0
|
|
22
47
|
|
|
23
48
|
**Starting from version 0.5.0, this package has migrated to ESM (ECMAScript Modules) format.**
|
|
@@ -58,7 +83,7 @@ import RestService, { FileService } from '@ticatec/restful_service_api';
|
|
|
58
83
|
|
|
59
84
|
// Your implementation of RestService interface
|
|
60
85
|
class MyApiClient implements RestService {
|
|
61
|
-
async get(url: string, params?: any, dataProcessor?: DataProcessor) {
|
|
86
|
+
async get(url: string, params?: any, dataProcessor?: DataProcessor, headers?: Record<string, string>) {
|
|
62
87
|
// Implementation here
|
|
63
88
|
}
|
|
64
89
|
|
|
@@ -108,7 +133,7 @@ The main interface for standard HTTP REST operations:
|
|
|
108
133
|
|
|
109
134
|
```typescript
|
|
110
135
|
interface RestService {
|
|
111
|
-
get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
|
|
136
|
+
get(url: string, params?: any, dataProcessor?: DataProcessor, headers?: Record<string, string>): Promise<any>;
|
|
112
137
|
post(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
113
138
|
put(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
114
139
|
patch(url: string, data?: any, options?: RestfulOptions): Promise<any>;
|
|
@@ -130,11 +155,13 @@ interface FileService {
|
|
|
130
155
|
|
|
131
156
|
### RestService Methods
|
|
132
157
|
|
|
133
|
-
#### `get(url, params?, dataProcessor?)`
|
|
158
|
+
#### `get(url, params?, dataProcessor?, headers?)`
|
|
134
159
|
Performs HTTP GET request to retrieve a resource.
|
|
135
160
|
- **url**: The endpoint URL
|
|
136
161
|
- **params**: Query parameters (optional)
|
|
137
162
|
- **dataProcessor**: Function to process response data (optional)
|
|
163
|
+
- **headers**: Custom request headers for this single call (optional), e.g. for a conditional
|
|
164
|
+
request: `{ 'If-None-Match': contentHash }`
|
|
138
165
|
|
|
139
166
|
#### `post(url, data?, options?)`
|
|
140
167
|
Performs HTTP POST request to create a new resource.
|
|
@@ -142,7 +169,8 @@ Performs HTTP POST request to create a new resource.
|
|
|
142
169
|
- **data**: Request payload (optional)
|
|
143
170
|
- **options**: Optional configuration object containing:
|
|
144
171
|
- **params**: Query parameters (optional)
|
|
145
|
-
- **
|
|
172
|
+
- **headers**: Custom request headers for this single call (optional). Use this to override
|
|
173
|
+
the default `Content-Type` (`application/json`), e.g. `{ 'Content-Type': 'multipart/form-data' }`
|
|
146
174
|
- **dataProcessor**: Function to process response data (optional)
|
|
147
175
|
|
|
148
176
|
#### `put(url, data?, options?)`
|
|
@@ -151,7 +179,7 @@ Performs HTTP PUT request to update an entire resource.
|
|
|
151
179
|
- **data**: Request payload (optional)
|
|
152
180
|
- **options**: Optional configuration object containing:
|
|
153
181
|
- **params**: Query parameters (optional)
|
|
154
|
-
- **
|
|
182
|
+
- **headers**: Custom request headers for this single call (optional)
|
|
155
183
|
- **dataProcessor**: Function to process response data (optional)
|
|
156
184
|
|
|
157
185
|
#### `patch(url, data?, options?)`
|
|
@@ -160,7 +188,7 @@ Performs HTTP PATCH request to partially update a resource.
|
|
|
160
188
|
- **data**: Request payload with fields to update (optional)
|
|
161
189
|
- **options**: Optional configuration object containing:
|
|
162
190
|
- **params**: Query parameters (optional)
|
|
163
|
-
- **
|
|
191
|
+
- **headers**: Custom request headers for this single call (optional)
|
|
164
192
|
- **dataProcessor**: Function to process response data (optional)
|
|
165
193
|
|
|
166
194
|
#### `del(url, data?, options?)`
|
|
@@ -169,7 +197,7 @@ Performs HTTP DELETE request to delete a resource.
|
|
|
169
197
|
- **data**: Request body data (optional)
|
|
170
198
|
- **options**: Optional configuration object containing:
|
|
171
199
|
- **params**: Query parameters (optional)
|
|
172
|
-
- **
|
|
200
|
+
- **headers**: Custom request headers for this single call (optional)
|
|
173
201
|
- **dataProcessor**: Function to process response data (optional)
|
|
174
202
|
|
|
175
203
|
### FileService Methods
|
|
@@ -231,7 +259,7 @@ import {
|
|
|
231
259
|
// RestfulOptions for configuring requests
|
|
232
260
|
const options: RestfulOptions = {
|
|
233
261
|
params: { page: 1, limit: 10 },
|
|
234
|
-
|
|
262
|
+
headers: { 'Content-Type': 'application/json' },
|
|
235
263
|
dataProcessor: (data: any) => data.results || data
|
|
236
264
|
};
|
|
237
265
|
|
|
@@ -277,8 +305,35 @@ import {
|
|
|
277
305
|
TYPE_TEXT
|
|
278
306
|
} from '@ticatec/restful_service_api';
|
|
279
307
|
|
|
280
|
-
// Usage
|
|
281
|
-
await api.post('/upload', data, {
|
|
308
|
+
// Usage - set a header explicitly via RestfulOptions.headers
|
|
309
|
+
await api.post('/upload', data, { headers: { [CONTENT_TYPE_NAME]: TYPE_JSON } });
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Custom Headers (e.g. Conditional Requests)
|
|
313
|
+
|
|
314
|
+
`RestfulOptions.headers` (and the 4th `headers` parameter of `get()`) let you attach custom
|
|
315
|
+
request headers to a single call. A common use case is a conditional GET based on a
|
|
316
|
+
previously-cached ETag/hash:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// First request: no cached hash yet
|
|
320
|
+
const pack = await api.get('/messages/node1');
|
|
321
|
+
localStorage.setItem('node1-hash', pack.contentHash);
|
|
322
|
+
|
|
323
|
+
// Later: send the cached hash as If-None-Match
|
|
324
|
+
const cachedHash = localStorage.getItem('node1-hash');
|
|
325
|
+
try {
|
|
326
|
+
const updated = await api.get('/messages/node1', undefined, undefined, {
|
|
327
|
+
'If-None-Match': cachedHash ?? ''
|
|
328
|
+
});
|
|
329
|
+
// Server responded 200 - content changed, use `updated`
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (error instanceof ApiError && Number(error.status) === 304) {
|
|
332
|
+
// Server responded 304 Not Modified - the local cache is still valid
|
|
333
|
+
} else {
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
282
337
|
```
|
|
283
338
|
|
|
284
339
|
## Implementation Example
|
|
@@ -308,48 +363,45 @@ class FetchRestService implements RestService {
|
|
|
308
363
|
this.postInterceptor = postInterceptor;
|
|
309
364
|
}
|
|
310
365
|
|
|
311
|
-
async get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any> {
|
|
366
|
+
async get(url: string, params?: any, dataProcessor?: DataProcessor, headers?: Record<string, string>): Promise<any> {
|
|
312
367
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
313
|
-
return this.request('GET', url + queryString, null,
|
|
368
|
+
return this.request('GET', url + queryString, null, headers, dataProcessor);
|
|
314
369
|
}
|
|
315
370
|
|
|
316
371
|
async post(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
317
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
318
372
|
const params = options?.params;
|
|
319
373
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
320
|
-
return this.request('POST', url + queryString, data,
|
|
374
|
+
return this.request('POST', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
321
375
|
}
|
|
322
376
|
|
|
323
377
|
async put(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
324
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
325
378
|
const params = options?.params;
|
|
326
379
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
327
|
-
return this.request('PUT', url + queryString, data,
|
|
380
|
+
return this.request('PUT', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
328
381
|
}
|
|
329
382
|
|
|
330
383
|
async patch(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
331
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
332
384
|
const params = options?.params;
|
|
333
385
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
334
|
-
return this.request('PATCH', url + queryString, data,
|
|
386
|
+
return this.request('PATCH', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
335
387
|
}
|
|
336
388
|
|
|
337
389
|
async del(url: string, data?: any, options?: RestfulOptions): Promise<any> {
|
|
338
|
-
const contentType = options?.contentType || TYPE_JSON;
|
|
339
390
|
const params = options?.params;
|
|
340
391
|
const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
341
|
-
return this.request('DELETE', url + queryString, data,
|
|
392
|
+
return this.request('DELETE', url + queryString, data, options?.headers, options?.dataProcessor);
|
|
342
393
|
}
|
|
343
394
|
|
|
344
|
-
private async request(method: string, url: string, body?: any,
|
|
395
|
+
private async request(method: string, url: string, body?: any, customHeaders?: Record<string, string>, dataProcessor?: DataProcessor): Promise<any> {
|
|
345
396
|
const fullUrl = this.baseURL + url;
|
|
346
397
|
|
|
347
398
|
// Apply pre-interceptor
|
|
348
399
|
const interceptorResult = this.preInterceptor?.(method, fullUrl) || { headers: {} };
|
|
349
400
|
|
|
350
401
|
const headers = {
|
|
402
|
+
'Content-Type': TYPE_JSON,
|
|
351
403
|
...interceptorResult.headers,
|
|
352
|
-
...
|
|
404
|
+
...customHeaders
|
|
353
405
|
};
|
|
354
406
|
|
|
355
407
|
try {
|
package/dist/FileService.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type UploadCallback from "./UploadCallback";
|
|
2
|
-
import type { UploadProgress } from "./UploadCallback";
|
|
3
|
-
import type { DataProcessor } from "./RestService";
|
|
1
|
+
import type UploadCallback from "./UploadCallback.js";
|
|
2
|
+
import type { UploadProgress } from "./UploadCallback.js";
|
|
3
|
+
import type { DataProcessor } from "./RestService.js";
|
|
4
4
|
/**
|
|
5
5
|
* File service interface for file upload and download operations
|
|
6
6
|
*/
|
|
@@ -45,20 +45,20 @@ export default interface FileService {
|
|
|
45
45
|
* { userId: 123 },
|
|
46
46
|
* file,
|
|
47
47
|
* {
|
|
48
|
-
*
|
|
49
|
-
* console.log(`
|
|
48
|
+
* progressUpdate: (uploadBytes) => {
|
|
49
|
+
* console.log(`Uploaded: ${uploadBytes} bytes`);
|
|
50
50
|
* },
|
|
51
51
|
* onCompleted: (data) => {
|
|
52
52
|
* console.log('Upload complete:', data);
|
|
53
53
|
* },
|
|
54
|
-
*
|
|
54
|
+
* handleError: (error) => {
|
|
55
55
|
* console.error('Upload failed:', error);
|
|
56
56
|
* }
|
|
57
57
|
* }
|
|
58
58
|
* );
|
|
59
59
|
*
|
|
60
60
|
* // Cancel the upload
|
|
61
|
-
* progress.
|
|
61
|
+
* progress.cancel();
|
|
62
62
|
* ```
|
|
63
63
|
*/
|
|
64
64
|
asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
|
package/dist/RestService.d.ts
CHANGED
|
@@ -31,17 +31,13 @@ export type PostInterceptor = (data: any) => Promise<any>;
|
|
|
31
31
|
/**
|
|
32
32
|
* Error handler function type for handling request errors
|
|
33
33
|
* @param ex The error object
|
|
34
|
-
* @returns
|
|
34
|
+
* @returns Optional boolean or void. Errors always reject the returned Promise.
|
|
35
35
|
*/
|
|
36
|
-
export type ErrorHandler = (ex: Error) => boolean;
|
|
36
|
+
export type ErrorHandler = (ex: Error) => boolean | void;
|
|
37
37
|
/**
|
|
38
38
|
* RESTful API request options
|
|
39
39
|
*/
|
|
40
40
|
export type RestfulOptions<T = any> = {
|
|
41
|
-
/**
|
|
42
|
-
* Optional Content-Type header, defaults to 'application/json'
|
|
43
|
-
*/
|
|
44
|
-
contentType?: string;
|
|
45
41
|
/**
|
|
46
42
|
* Optional data processing function to transform response data before returning
|
|
47
43
|
*/
|
|
@@ -50,6 +46,13 @@ export type RestfulOptions<T = any> = {
|
|
|
50
46
|
* Optional query parameters object that will be converted to URL query string
|
|
51
47
|
*/
|
|
52
48
|
params?: any;
|
|
49
|
+
/**
|
|
50
|
+
* Optional custom request headers for this single call (e.g. { 'If-None-Match': contentHash },
|
|
51
|
+
* or { 'Content-Type': 'multipart/form-data' } to override the default JSON content type).
|
|
52
|
+
* These are merged on top of any headers produced by the PreInterceptor, and take precedence
|
|
53
|
+
* over them when the same header name is used.
|
|
54
|
+
*/
|
|
55
|
+
headers?: Record<string, string>;
|
|
53
56
|
};
|
|
54
57
|
/**
|
|
55
58
|
* HTTP header name for Content-Type
|
|
@@ -76,6 +79,7 @@ export default interface RestService {
|
|
|
76
79
|
* @param url The target URL path for the request
|
|
77
80
|
* @param params Query parameters object that will be converted to URL query string
|
|
78
81
|
* @param dataProcessor Optional data processing function to transform response data before returning
|
|
82
|
+
* @param headers Optional custom request headers for this single call (e.g. conditional GET via If-None-Match)
|
|
79
83
|
* @returns Promise that resolves to the server response data
|
|
80
84
|
*
|
|
81
85
|
* @example
|
|
@@ -88,14 +92,17 @@ export default interface RestService {
|
|
|
88
92
|
*
|
|
89
93
|
* // GET with data processor
|
|
90
94
|
* const users = await restService.get('/api/users', null, (data) => data.items);
|
|
95
|
+
*
|
|
96
|
+
* // GET with a custom header (e.g. conditional GET)
|
|
97
|
+
* const pack = await restService.get('/api/messages/node1', null, undefined, { 'If-None-Match': contentHash });
|
|
91
98
|
* ```
|
|
92
99
|
*/
|
|
93
|
-
get<T = any>(url: string, params?: any, dataProcessor?: DataProcessor<T>): Promise<T>;
|
|
100
|
+
get<T = any>(url: string, params?: any, dataProcessor?: DataProcessor<T>, headers?: Record<string, string>): Promise<T>;
|
|
94
101
|
/**
|
|
95
102
|
* Performs an HTTP POST request to create a new resource
|
|
96
103
|
* @param url The target URL path for the request
|
|
97
104
|
* @param data Request body data to be sent, typically an object or string
|
|
98
|
-
* @param options Optional request configuration options, including
|
|
105
|
+
* @param options Optional request configuration options, including headers and dataProcessor
|
|
99
106
|
* @returns Promise that resolves to the server response data
|
|
100
107
|
*
|
|
101
108
|
* @example
|
|
@@ -103,9 +110,9 @@ export default interface RestService {
|
|
|
103
110
|
* // Simple POST request
|
|
104
111
|
* const newUser = await restService.post('/api/users', { name: 'John', age: 30 });
|
|
105
112
|
*
|
|
106
|
-
* // POST with custom
|
|
113
|
+
* // POST with a custom Content-Type header
|
|
107
114
|
* const result = await restService.post('/api/data', formData, {
|
|
108
|
-
*
|
|
115
|
+
* headers: { 'Content-Type': 'multipart/form-data' }
|
|
109
116
|
* });
|
|
110
117
|
*
|
|
111
118
|
* // POST with data processor
|
|
@@ -119,7 +126,7 @@ export default interface RestService {
|
|
|
119
126
|
* Performs an HTTP PUT request to update an existing resource
|
|
120
127
|
* @param url The target URL path for the request
|
|
121
128
|
* @param data Optional request body data to be sent for updating the resource
|
|
122
|
-
* @param options Optional request configuration options, including
|
|
129
|
+
* @param options Optional request configuration options, including headers and dataProcessor
|
|
123
130
|
* @returns Promise that resolves to the server response data
|
|
124
131
|
*
|
|
125
132
|
* @example
|
|
@@ -136,7 +143,7 @@ export default interface RestService {
|
|
|
136
143
|
* Performs an HTTP DELETE request to delete a resource
|
|
137
144
|
* @param url The target URL path for the request
|
|
138
145
|
* @param data Optional request body data, some DELETE operations may require sending data
|
|
139
|
-
* @param options Optional request configuration options, including
|
|
146
|
+
* @param options Optional request configuration options, including headers and dataProcessor
|
|
140
147
|
* @returns Promise that resolves to the server response data
|
|
141
148
|
*
|
|
142
149
|
* @example
|
|
@@ -153,7 +160,7 @@ export default interface RestService {
|
|
|
153
160
|
* Performs an HTTP PATCH request to partially update a resource
|
|
154
161
|
* @param url The target URL path for the request
|
|
155
162
|
* @param data Optional request body data to be sent for partially updating the resource
|
|
156
|
-
* @param options Optional request configuration options, including
|
|
163
|
+
* @param options Optional request configuration options, including headers and dataProcessor
|
|
157
164
|
* @returns Promise that resolves to the server response data
|
|
158
165
|
*
|
|
159
166
|
* @example
|
package/dist/UploadCallback.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import ApiError from "./ApiError";
|
|
2
|
-
import type { ApiErrorPayload } from "./ApiError";
|
|
3
|
-
import RestService from "./RestService";
|
|
4
|
-
import FileService from "./FileService";
|
|
5
|
-
import { ErrorHandler, PostInterceptor, PreInterceptor, DataProcessor } from "./RestService";
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { RestfulOptions } from "./RestService";
|
|
1
|
+
import ApiError from "./ApiError.js";
|
|
2
|
+
import type { ApiErrorPayload } from "./ApiError.js";
|
|
3
|
+
import RestService from "./RestService.js";
|
|
4
|
+
import FileService from "./FileService.js";
|
|
5
|
+
import type { ErrorHandler, PostInterceptor, PreInterceptor, DataProcessor, PreInterceptorResult, RestfulOptions } from "./RestService.js";
|
|
6
|
+
import { CONTENT_TYPE_NAME, TYPE_JSON, TYPE_HTML, TYPE_TEXT } from "./RestService.js";
|
|
7
|
+
import type UploadCallback from "./UploadCallback.js";
|
|
8
|
+
import type { UploadProgress, ProgressUpdate, OnCompleted, OnUploaded } from "./UploadCallback.js";
|
|
10
9
|
export default RestService;
|
|
11
10
|
export { ApiError };
|
|
12
11
|
export type { ApiErrorPayload };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ApiError from "./ApiError";
|
|
2
|
-
import { CONTENT_TYPE_NAME, TYPE_JSON, TYPE_HTML, TYPE_TEXT } from "./RestService";
|
|
1
|
+
import ApiError from "./ApiError.js";
|
|
2
|
+
import { CONTENT_TYPE_NAME, TYPE_JSON, TYPE_HTML, TYPE_TEXT } from "./RestService.js";
|
|
3
3
|
export { ApiError };
|
|
4
4
|
export { CONTENT_TYPE_NAME, TYPE_JSON, TYPE_HTML, TYPE_TEXT };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@ticatec/restful_service_api",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "A lightweight TypeScript RESTful API client for browsers with error handling. (ESM only, v0.6.0+)",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|