@superutils/fetch 1.5.14 → 1.5.16
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.md +217 -212
- package/dist/browser/index.min.js.map +1 -1
- package/dist/index.d.cts +80 -27
- package/dist/index.d.ts +80 -27
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -14,25 +14,26 @@ For full API reference check out the [docs page](https://alien45.github.io/super
|
|
|
14
14
|
|
|
15
15
|
- [Features](#features)
|
|
16
16
|
- [Installation](#installation)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
- [NPM](#npm)
|
|
18
|
+
- [CDN / Browser](#cdn--browser)
|
|
19
|
+
- [Defaults](#defaults)
|
|
20
|
+
- [Timeout](#timeout)
|
|
21
|
+
- [Conent Type](#content-type)
|
|
22
|
+
- [Response Parsing](#fetch-as)
|
|
23
23
|
- [Usage](#usage)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
- [`fetch()`](#fetch): drop-in replacement for built-in `fetch()`
|
|
25
|
+
- [`TimeoutPromise` Instance](#promise-features): finer control over the request
|
|
26
|
+
- [`Method Specific Functions`](#methods)
|
|
27
|
+
- [`fetch.get()`](#fetch-get)
|
|
28
|
+
- [`fetch.get.deferred()`](#fetch-deferred): cancellable and debounced or throttled `fetch()`
|
|
29
|
+
- [`fetch.post()`](#post): make post requests
|
|
30
|
+
- [`fetch.post.deferred()`](#post-deferred): cancellable and debounced or throttled `post()`
|
|
31
|
+
- [`Interceptors/Transformers`](#interceptors)
|
|
32
|
+
- [`Retry`](#retry) Retry on request failure
|
|
33
|
+
- [`Timeout`](#timeout) Abort request on timeout
|
|
34
|
+
- [`createClient()`](#create-client):
|
|
35
|
+
- [`createPostClient()`](#create-post-client):
|
|
36
|
+
- [`fetchFunc`](#fetch-func): Using with third-party libraries (e.g., Axios)
|
|
36
37
|
|
|
37
38
|
## Features
|
|
38
39
|
|
|
@@ -141,8 +142,8 @@ To retrieve the response in a different format (e.g., as text, a blob, or the ra
|
|
|
141
142
|
import fetch, { FetchAs } from '@superutils/fetch'
|
|
142
143
|
|
|
143
144
|
fetch
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
.get('[DUMMYJSON-DOT-COM]/products/1', { as: FetchAs.text })
|
|
146
|
+
.then(console.log)
|
|
146
147
|
```
|
|
147
148
|
|
|
148
149
|
> **Note:** To ensure type safety, the `as` property is excluded from `fetch.defaults` in TypeScript. Since this option determines the function's return type, setting it globally would prevent accurate type inference for individual requests.
|
|
@@ -159,8 +160,8 @@ Use as a drop-in replacement to built-in `fetch()`.
|
|
|
159
160
|
import fetch from '@superutils/fetch'
|
|
160
161
|
|
|
161
162
|
fetch('[DUMMYJSON-DOT-COM]/products/1')
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
.then(response => response.json())
|
|
164
|
+
.then(console.log)
|
|
164
165
|
```
|
|
165
166
|
|
|
166
167
|
<div id="promise-features"></div>
|
|
@@ -179,11 +180,11 @@ const request = fetch('[DUMMYJSON-DOT-COM]/products/1')
|
|
|
179
180
|
console.log(request.pending) // true
|
|
180
181
|
|
|
181
182
|
request.then(() => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
183
|
+
console.log(request.resolved) // true
|
|
184
|
+
console.log(request.pending) // false
|
|
185
|
+
console.log(request.rejected) // false
|
|
186
|
+
console.log(request.aborted) // false
|
|
187
|
+
console.log(request.timedout) // false
|
|
187
188
|
})
|
|
188
189
|
```
|
|
189
190
|
|
|
@@ -200,7 +201,7 @@ request.then(result => console.log(result), console.warn)
|
|
|
200
201
|
// Add a callback to do stuff whenever request is aborted externally.
|
|
201
202
|
// This will not be invoked if fetch fails or resolves (promise finalized naturally) using the Promise executor.
|
|
202
203
|
request.onEarlyFinalize.push((resolved, valueOrReason) =>
|
|
203
|
-
|
|
204
|
+
console.log('Aborted externally:', { resolved, valueOrReason }),
|
|
204
205
|
)
|
|
205
206
|
|
|
206
207
|
// resolve/reject before the promise is finalized
|
|
@@ -260,8 +261,8 @@ Equivalent to `fetch(url, { method: 'get', as: 'json' })`.
|
|
|
260
261
|
import fetch from '@superutils/fetch'
|
|
261
262
|
|
|
262
263
|
fetch
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
.get('[DUMMYJSON-DOT-COM]/products/1')
|
|
265
|
+
.then(product => console.log({ product }))
|
|
265
266
|
```
|
|
266
267
|
|
|
267
268
|
<div id="fetch-deferred"></div>
|
|
@@ -275,22 +276,22 @@ import fetch from '@superutils/fetch'
|
|
|
275
276
|
|
|
276
277
|
// Create a debounced search function with a 300ms delay.
|
|
277
278
|
const searchProducts = fetch.get.deferred({
|
|
278
|
-
|
|
279
|
-
|
|
279
|
+
delay: 300, // Debounce delay
|
|
280
|
+
resolveIgnored: 'WITH_UNDEFINED', // Ignored (aborted) promises will resolve with `undefined`
|
|
280
281
|
})
|
|
281
282
|
|
|
282
283
|
// User types 'iphone'
|
|
283
284
|
searchProducts('[DUMMYJSON-DOT-COM]/products/search?q=iphone').then(result => {
|
|
284
|
-
|
|
285
|
+
console.log('Result for "iphone":', result)
|
|
285
286
|
})
|
|
286
287
|
|
|
287
288
|
// Before 300ms has passed, the user continues typing 'iphone 12'
|
|
288
289
|
setTimeout(() => {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
290
|
+
searchProducts('[DUMMYJSON-DOT-COM]/products/search?q=iphone 12').then(
|
|
291
|
+
result => {
|
|
292
|
+
console.log('Result for "iphone 12":', result)
|
|
293
|
+
},
|
|
294
|
+
)
|
|
294
295
|
}, 200)
|
|
295
296
|
// Outcome:
|
|
296
297
|
// The first request for "iphone" is aborted.
|
|
@@ -305,18 +306,18 @@ setTimeout(() => {
|
|
|
305
306
|
- **`delay: 0`**: Disables debouncing and throttling, enabling sequential/queue mode. Both requests ("iphone"
|
|
306
307
|
and "iphone 12") would execute, but one after the other, never simultaneously.
|
|
307
308
|
- **`resolveIgnored` (enum)**: Controls how the promise for an aborted request (like the first "iphone" call) resolves.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
309
|
+
1. `ResolveIgnored.WITH_UNDEFINED` (used in the example): The promise for the aborted "iphone"
|
|
310
|
+
request resolves with `undefined`.
|
|
311
|
+
2. `ResolveIgnored.WITH_LAST`: The promise for the aborted "iphone" request waits and resolves with the result
|
|
312
|
+
of the final "iphone 12" request. Both promises resolve to the same value.
|
|
313
|
+
3. `ResolveIgnored.NEVER`: The promise for the aborted "iphone" request is neither resolved nor rejected.
|
|
314
|
+
It will remain pending indefinitely.
|
|
314
315
|
- **`resolveError` (enum)**: Controls how failed requests are handled.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
1. `ResolveError.NEVER`: The promise for a failed request will neither resolve nor reject, causing it to remain pending indefinitely.
|
|
317
|
+
> **Warning:** Use with caution, as this may lead to memory leaks if not handled properly.
|
|
318
|
+
2. `ResolveError.WITH_ERROR`: The promise resolves with the `FetchError` object instead of being rejected.
|
|
319
|
+
3. `ResolveError.WITH_UNDEFINED`: The promise resolves with an `undefined` value upon failure.
|
|
320
|
+
4. `ResolveError.REJECT`: (Default) The promise is rejected with a `FetchError`, adhering to standard promise behavior.
|
|
320
321
|
|
|
321
322
|
<!-- #### Using defaults to reduce redundancy
|
|
322
323
|
|
|
@@ -360,8 +361,8 @@ import fetch from '@superutils/fetch'
|
|
|
360
361
|
const newProduct = { title: 'Perfume Oil' }
|
|
361
362
|
|
|
362
363
|
fetch.post('[DUMMYJSON-DOT-COM]/products/add', newProduct).then(
|
|
363
|
-
|
|
364
|
-
|
|
364
|
+
createdProduct => console.log('Product created:', createdProduct),
|
|
365
|
+
error => console.error('Failed to create product:', error),
|
|
365
366
|
)
|
|
366
367
|
```
|
|
367
368
|
|
|
@@ -379,13 +380,13 @@ import PromisE from '@superutils/promise'
|
|
|
379
380
|
|
|
380
381
|
// Create a throttled function to auto-save product updates.
|
|
381
382
|
const saveProductThrottled = fetch.post.deferred(
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
383
|
+
{
|
|
384
|
+
delay: 1000, // Throttle window of 1 second
|
|
385
|
+
throttle: true,
|
|
386
|
+
trailing: true, // Ensures the very last update is always saved
|
|
387
|
+
onResult: product => console.log(`[Saved] Product: ${product.title}`),
|
|
388
|
+
},
|
|
389
|
+
'[DUMMYJSON-DOT-COM]/products/add', // Default URL
|
|
389
390
|
)
|
|
390
391
|
// Simulate a user typing quickly, triggering multiple saves.
|
|
391
392
|
console.log('User starts typing...')
|
|
@@ -417,41 +418,40 @@ let currentRefreshToken = ''
|
|
|
417
418
|
// Create a debounced function to refresh the auth token.
|
|
418
419
|
// It waits 300ms after the last call before executing.
|
|
419
420
|
const requestNewToken = fetch.post.deferred(
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
421
|
+
{
|
|
422
|
+
delay: 300, // debounce delay
|
|
423
|
+
onResult: ({ refreshToken = '' }) => {
|
|
424
|
+
console.log(
|
|
425
|
+
`Auth token successfully refreshed at ${new Date().toISOString()}`,
|
|
426
|
+
)
|
|
427
|
+
currentRefreshToken = refreshToken
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
'[DUMMYJSON-DOT-COM]/auth/refresh', // Default URL
|
|
431
|
+
() => ({
|
|
432
|
+
refreshToken: currentRefreshToken,
|
|
433
|
+
expiresInMins: 30,
|
|
434
|
+
}),
|
|
434
435
|
)
|
|
435
436
|
|
|
436
|
-
// First authenticate user to get the initial refresh token and then request new referesh tokens
|
|
437
437
|
// First authenticate user to get the initial refresh token and then request new refresh tokens
|
|
438
438
|
fetch
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
439
|
+
.post<{ refreshToken: string }>(
|
|
440
|
+
'[DUMMYJSON-DOT-COM]/auth/login',
|
|
441
|
+
{
|
|
442
|
+
username: 'emilys',
|
|
443
|
+
password: 'emilyspass',
|
|
444
|
+
expiresInMins: 30,
|
|
445
|
+
},
|
|
446
|
+
{ credentials: 'include' },
|
|
447
|
+
)
|
|
448
|
+
.then(result => {
|
|
449
|
+
currentRefreshToken = result?.refreshToken
|
|
450
|
+
|
|
451
|
+
requestNewToken() // Called at 0ms
|
|
452
|
+
PromisE.delay(50, requestNewToken) // Called at 50ms
|
|
453
|
+
PromisE.delay(100, requestNewToken) // Called at 100ms
|
|
454
|
+
}, console.error)
|
|
455
455
|
// Outcome:
|
|
456
456
|
// The first two calls are aborted by the debounce mechanism.
|
|
457
457
|
// Only the final call executes, 300ms after it was made (at the 400ms mark).
|
|
@@ -467,8 +467,8 @@ The following interceptor callbacks allow intercepting and/or transforming at di
|
|
|
467
467
|
#### Interceptor types (executed in sequence):
|
|
468
468
|
|
|
469
469
|
1. `request`: Request interceptors are executed before a HTTP request is made.
|
|
470
|
-
|
|
471
|
-
|
|
470
|
+
- To transform the URL simply return a new or modified URL.
|
|
471
|
+
- To transform `fetch` options simply modify the options parameter
|
|
472
472
|
2. `response`: Response interceptors are executed after receiving a `fetch` Response regardless of the HTTP status code.
|
|
473
473
|
3. `result`: Result interceptors are executed before returning the result. To transform the result simply return a new value.
|
|
474
474
|
PS: if the value of `options.as` is `FetchAs.response` (`"response"`), the value received in result will be a `Response` object.
|
|
@@ -480,8 +480,8 @@ The following interceptor callbacks allow intercepting and/or transforming at di
|
|
|
480
480
|
- If an exception is raised while executing the interceptors, it will be gracefully ignored.
|
|
481
481
|
- Value returned (transformed) by an interceptor will be carried over to the subsequent interceptor of the same type.
|
|
482
482
|
- There are 2 category of interceptors:
|
|
483
|
-
|
|
484
|
-
|
|
483
|
+
- Local: interceptors provided when making a request.
|
|
484
|
+
- Global: interceptors that are executed application-wide on every request. Global interceptors can be added/accessed at `fetch.defaults.interceptors`. Global interceptors are always executed before local interceptors.
|
|
485
485
|
|
|
486
486
|
**Example: Interceptor usage**
|
|
487
487
|
|
|
@@ -489,51 +489,48 @@ The following interceptor callbacks allow intercepting and/or transforming at di
|
|
|
489
489
|
import fetch, { FetchError } from '@superutils/fetch'
|
|
490
490
|
|
|
491
491
|
const interceptors = {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
return result
|
|
531
|
-
},
|
|
532
|
-
],
|
|
492
|
+
error: [
|
|
493
|
+
(err, url, options) => {
|
|
494
|
+
console.log('Request failed', err, url, options)
|
|
495
|
+
// return nothing/undefined to keep the error unchanged
|
|
496
|
+
// or return modified/new error
|
|
497
|
+
err.message = 'My custom error message!'
|
|
498
|
+
// or create a new FetchError by cloning it (make sure all the required properties are set correctly)
|
|
499
|
+
return err.clone('My custom error message!')
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
request: [
|
|
503
|
+
(url, options) => {
|
|
504
|
+
// add extra headers or modify request options here
|
|
505
|
+
options.headers.append('x-custom-header', 'some value')
|
|
506
|
+
|
|
507
|
+
// transform the URL by returning a modified URL
|
|
508
|
+
return url + '?param=value'
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
response: [
|
|
512
|
+
(response, url, options) => {
|
|
513
|
+
if (response.ok) return
|
|
514
|
+
console.log('request was not successful', { url, options })
|
|
515
|
+
|
|
516
|
+
// You can transform the response by returning different `Response` object or even make a completely new HTTP request.
|
|
517
|
+
// The subsequent response interceptors will receive the returned response
|
|
518
|
+
return fetch('[DUMMYJSON-DOT-COM]/products/1') // promise will be resolved automatically
|
|
519
|
+
},
|
|
520
|
+
],
|
|
521
|
+
result: [
|
|
522
|
+
(result, url, options) => {
|
|
523
|
+
const productId = Number(new URL(url).pathname.split('/products/')[1])
|
|
524
|
+
if (options.method === 'get' && !Number.isNaN(productId)) {
|
|
525
|
+
result.title ??= 'Unknown title'
|
|
526
|
+
}
|
|
527
|
+
return result
|
|
528
|
+
},
|
|
529
|
+
],
|
|
533
530
|
}
|
|
534
531
|
fetch
|
|
535
|
-
|
|
536
|
-
|
|
532
|
+
.get('[DUMMYJSON-DOT-COM]/products/1', { interceptors })
|
|
533
|
+
.then(product => console.log({ product }))
|
|
537
534
|
```
|
|
538
535
|
|
|
539
536
|
**Example: Add global request and error interceptors**
|
|
@@ -544,14 +541,14 @@ import fetch from '@superutils/fetch'
|
|
|
544
541
|
const { interceptors } = fetch.defaults
|
|
545
542
|
|
|
546
543
|
interceptors.request.push((url, options) => {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
544
|
+
// a headers to all requests make by the application
|
|
545
|
+
// add headers to all requests made by the application
|
|
546
|
+
options.headers.append('x-auth', 'token')
|
|
550
547
|
})
|
|
551
548
|
|
|
552
549
|
interceptors.error.push((err, url, options) => {
|
|
553
|
-
|
|
554
|
-
|
|
550
|
+
// log whenever a request fails
|
|
551
|
+
console.log('Error interceptor', err)
|
|
555
552
|
})
|
|
556
553
|
|
|
557
554
|
// Each time a requst is made using @superutils/fetch, the above interceptors will be executed when appropriate
|
|
@@ -568,19 +565,12 @@ The `retry` option provides a robust mechanism to automatically re-attempt faile
|
|
|
568
565
|
import fetch from '@superutils/fetch'
|
|
569
566
|
|
|
570
567
|
fetch
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
// Mke sure to clone the response if result stream must be consumed here.
|
|
578
|
-
// Cloning is required to avoid "body stream already read" error.
|
|
579
|
-
const result = await response.clone().json()
|
|
580
|
-
return result !== 'expected value'
|
|
581
|
-
},
|
|
582
|
-
})
|
|
583
|
-
.then(console.log)
|
|
568
|
+
.get('[DUMMYJSON-DOT-COM]/products/1', {
|
|
569
|
+
retry: 3, // If request fails, retry up to three more times
|
|
570
|
+
// Retry on rate limits (429) or transient server errors (5xx).
|
|
571
|
+
retryIf: r => r.status === 429 || r.status >= 500,
|
|
572
|
+
})
|
|
573
|
+
.then(console.log)
|
|
584
574
|
```
|
|
585
575
|
|
|
586
576
|
<div id="create-client"></div>
|
|
@@ -596,42 +586,42 @@ import { createClient } from '@superutils/fetch'
|
|
|
596
586
|
|
|
597
587
|
// Create a "GET" client with default headers and a 5-second timeout
|
|
598
588
|
const apiClient = createClient(
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
589
|
+
{
|
|
590
|
+
// fixed options (cannot be overridden)
|
|
591
|
+
method: 'get',
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
// common options (can be overridden)
|
|
595
|
+
headers: {
|
|
596
|
+
Authorization: 'Bearer my-secret-token',
|
|
597
|
+
'Content-Type': 'application/json',
|
|
598
|
+
},
|
|
599
|
+
timeout: 5000,
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
// defer options (can be overridden)
|
|
603
|
+
delay: 300,
|
|
604
|
+
retry: 2, // If request fails, retry up to two more times
|
|
605
|
+
},
|
|
616
606
|
)
|
|
617
607
|
|
|
618
608
|
// Use it just like the standard fetch
|
|
619
609
|
apiClient('[DUMMYJSON-DOT-COM]/products/1', {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
610
|
+
// The 'method' property cannot be overridden as it is used in the fixed options when creating the client.
|
|
611
|
+
// In TypeScript, the compiler will not allow this property.
|
|
612
|
+
// In Javascript, it will simply be ignored.
|
|
613
|
+
// method: 'post',
|
|
614
|
+
timeout: 3000, // The 'timeout' property can be overridden
|
|
625
615
|
}).then(console.log, console.warn)
|
|
626
616
|
|
|
627
617
|
// create a deferred client using "apiClient"
|
|
628
618
|
const deferredClient = apiClient.deferred(
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
619
|
+
{ retry: 0 }, // disable retrying by overriding the `retry` defer option
|
|
620
|
+
'[DUMMYJSON-DOT-COM]/products/1',
|
|
621
|
+
{ timeout: 3000 },
|
|
632
622
|
)
|
|
633
623
|
deferredClient({ timeout: 10000 }) // timeout is overridden by individual request
|
|
634
|
-
|
|
624
|
+
.then(console.log, console.warn)
|
|
635
625
|
```
|
|
636
626
|
|
|
637
627
|
<div id="create-post-client"></div>
|
|
@@ -647,57 +637,72 @@ import { createPostClient } from '@superutils/fetch'
|
|
|
647
637
|
|
|
648
638
|
// Create a POST client with 10-second as the default timeout
|
|
649
639
|
const postClient = createPostClient(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
640
|
+
{
|
|
641
|
+
headers: { 'content-type': 'application/json' },
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
method: 'post',
|
|
645
|
+
timeout: 10000,
|
|
646
|
+
},
|
|
657
647
|
)
|
|
658
648
|
|
|
659
649
|
// Invoking `postClient()` automatically applies the pre-configured options
|
|
660
650
|
postClient(
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
651
|
+
'[DUMMYJSON-DOT-COM]/products/add',
|
|
652
|
+
{ title: 'New Product' }, // data/body
|
|
653
|
+
{}, // other options
|
|
664
654
|
).then(result => console.log('Product created:', result))
|
|
665
655
|
|
|
666
656
|
// create a deferred client using "postClient"
|
|
667
657
|
const deferredPatchClient = postClient.deferred(
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
658
|
+
{
|
|
659
|
+
delay: 300,
|
|
660
|
+
// prints only successful results
|
|
661
|
+
onResult: result =>
|
|
662
|
+
console.log('Product updated using deferred function:', result),
|
|
663
|
+
},
|
|
664
|
+
'[DUMMYJSON-DOT-COM]/products/add',
|
|
665
|
+
undefined, // data to be provided later
|
|
666
|
+
{
|
|
667
|
+
method: 'patch', // default method for deferredPatchClient
|
|
668
|
+
timeout: 3000,
|
|
669
|
+
},
|
|
680
670
|
)
|
|
681
671
|
deferredPatchClient({ title: 'New title 1' }) // ignored by debounce
|
|
682
672
|
deferredPatchClient({ title: 'New title 2' }) // executed
|
|
683
673
|
```
|
|
684
674
|
|
|
685
|
-
<div id="
|
|
675
|
+
<div id="fetch-func"></div>
|
|
686
676
|
|
|
687
|
-
### `fetchFunc`: Using
|
|
677
|
+
### `fetchFunc`: Using with third-party libraries (e.g., Axios)
|
|
688
678
|
|
|
689
679
|
The `fetchFunc` option allows you to replace the default request engine. This enables the use of third-party libraries like `axios` while still leveraging `@superutils/fetch` features such as [retries](#retry), [timeouts](#timeout), [debouncing/throttling](#fetch-deferred), and [interceptors](#interceptors).
|
|
690
680
|
|
|
691
681
|
```typescript
|
|
692
|
-
import fetch, {
|
|
682
|
+
import fetch, {
|
|
683
|
+
FetchCustomOptions,
|
|
684
|
+
FetchFunc,
|
|
685
|
+
FetchOptions,
|
|
686
|
+
} from '@superutils/fetch'
|
|
693
687
|
import axios from 'axios'
|
|
694
688
|
|
|
689
|
+
type Product = {
|
|
690
|
+
id: number
|
|
691
|
+
title: string
|
|
692
|
+
}
|
|
695
693
|
fetch
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
694
|
+
.get<{ data: Product }>('[DUMMYJSON-DOT-COM]/products/1', {
|
|
695
|
+
/**
|
|
696
|
+
* Note: Ensure request options are compatible with the third-party
|
|
697
|
+
* engine's configuration schema.
|
|
698
|
+
*
|
|
699
|
+
* Check {@link FetchOptions} (includes `FetchCustomOptions`).
|
|
700
|
+
*/
|
|
701
|
+
fetchFunc: axios as FetchFunc,
|
|
702
|
+
|
|
703
|
+
// if request fails retry maximus 3 more times
|
|
704
|
+
retry: 3,
|
|
705
|
+
// ...additional options
|
|
706
|
+
})
|
|
707
|
+
.then(({ data }) => console.log({ product: data }))
|
|
703
708
|
```
|