fetch-request-browser 1.0.10 → 1.0.12

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 CHANGED
@@ -12,7 +12,7 @@ If you are working on a node-based environment, make use of [fetch-request-node]
12
12
 
13
13
  Install the package:
14
14
  ```bash
15
- npm install -S fetch-request-browser
15
+ npm i -S fetch-request-browser
16
16
  ```
17
17
 
18
18
  ### Examples
@@ -125,6 +125,7 @@ await sendPOST<IHTTPBinResponse>(
125
125
 
126
126
  <details>
127
127
  <summary><code>send</code></summary>
128
+ <br/>
128
129
 
129
130
  Builds and sends an HTTP Request based on the provided input and options.
130
131
  ```typescript
@@ -161,10 +162,12 @@ await sendPOST<IHTTPBinResponse>(
161
162
  // }
162
163
  // }
163
164
  ```
165
+ <br/>
164
166
  </details>
165
167
 
166
168
  <details>
167
169
  <summary><code>sendGET</code></summary>
170
+ <br/>
168
171
 
169
172
  Builds and sends a `GET` HTTP Request based on the provided input and options.
170
173
  ```typescript
@@ -197,10 +200,12 @@ await sendPOST<IHTTPBinResponse>(
197
200
  // }
198
201
  // }
199
202
  ```
203
+ <br/>
200
204
  </details>
201
205
 
202
206
  <details>
203
207
  <summary><code>sendPOST</code></summary>
208
+ <br/>
204
209
 
205
210
  Builds and sends a `POST` HTTP Request based on the provided input and options.
206
211
  ```typescript
@@ -249,10 +254,12 @@ await sendPOST<IHTTPBinResponse>(
249
254
  // }
250
255
  // }
251
256
  ```
257
+ <br/>
252
258
  </details>
253
259
 
254
260
  <details>
255
261
  <summary><code>sendPUT</code></summary>
262
+ <br/>
256
263
 
257
264
  Builds and sends a `PUT` HTTP Request based on the provided input and options.
258
265
  ```typescript
@@ -301,10 +308,12 @@ await sendPOST<IHTTPBinResponse>(
301
308
  // }
302
309
  // }
303
310
  ```
311
+ <br/>
304
312
  </details>
305
313
 
306
314
  <details>
307
315
  <summary><code>sendPATCH</code></summary>
316
+ <br/>
308
317
 
309
318
  Builds and sends a `PATCH` HTTP Request based on the provided input and options.
310
319
  ```typescript
@@ -353,10 +362,12 @@ await sendPOST<IHTTPBinResponse>(
353
362
  // }
354
363
  // }
355
364
  ```
365
+ <br/>
356
366
  </details>
357
367
 
358
368
  <details>
359
369
  <summary><code>sendDELETE</code></summary>
370
+ <br/>
360
371
 
361
372
  Builds and sends a `DELETE` HTTP Request based on the provided input and options.
362
373
  ```typescript
@@ -394,6 +405,7 @@ await sendPOST<IHTTPBinResponse>(
394
405
  // }
395
406
  // }
396
407
  ```
408
+ <br/>
397
409
  </details>
398
410
 
399
411
 
@@ -407,24 +419,29 @@ await sendPOST<IHTTPBinResponse>(
407
419
 
408
420
  <details>
409
421
  <summary><code>IRequestInput</code></summary>
422
+ <br/>
410
423
 
411
424
  The URL of the request's target.
412
425
  ```typescript
413
426
  type IRequestInput = string | URL;
414
427
  ```
428
+ <br/>
415
429
  </details>
416
430
 
417
431
  <details>
418
432
  <summary><code>IRequestMethod</code></summary>
433
+ <br/>
419
434
 
420
435
  The HTTP Methods supported by this library. To make use of a different one, pass the method name directly in the request options.
421
436
  ```typescript
422
437
  type IRequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
423
438
  ```
439
+ <br/>
424
440
  </details>
425
441
 
426
442
  <details>
427
443
  <summary><code>RequestInit</code></summary>
444
+ <br/>
428
445
 
429
446
  The [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) dictionary of the Fetch API represents the set of options that can be used to configure a fetch request.
430
447
  ```typescript
@@ -458,10 +475,12 @@ await sendPOST<IHTTPBinResponse>(
458
475
  window?: null;
459
476
  }
460
477
  ```
478
+ <br/>
461
479
  </details>
462
480
 
463
481
  <details>
464
482
  <summary><code>IRequestOptions</code></summary>
483
+ <br/>
465
484
 
466
485
  The options that can be applied when sending a Fetch Request.
467
486
  IMPORTANT: the reason RequestInit is extended is because in the original type, the body property does not accept plain objects. Even though this makes sense, utilities so the Request's body is always going to have a valid type.
@@ -475,19 +494,23 @@ await sendPOST<IHTTPBinResponse>(
475
494
  method: IRequestMethod;
476
495
  }
477
496
  ```
497
+ <br/>
478
498
  </details>
479
499
 
480
500
  <details>
481
501
  <summary><code>IResponseDataType</code></summary>
502
+ <br/>
482
503
 
483
504
  The type of data that will be extracted from the HTTP Response body.
484
505
  ```typescript
485
506
  type IResponseDataType = 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'text';
486
507
  ```
508
+ <br/>
487
509
  </details>
488
510
 
489
511
  <details>
490
512
  <summary><code>IOptions</code></summary>
513
+ <br/>
491
514
 
492
515
  The options object that can be passed and used for any request.
493
516
  ```typescript
@@ -515,10 +538,12 @@ await sendPOST<IHTTPBinResponse>(
515
538
  skipStatusCodeValidation: boolean;
516
539
  }
517
540
  ```
541
+ <br/>
518
542
  </details>
519
543
 
520
544
  <details>
521
545
  <summary><code>IRequestResponse<T></code></summary>
546
+ <br/>
522
547
 
523
548
  The object containing the result of the Request.
524
549
  ```typescript
@@ -536,6 +561,7 @@ await sendPOST<IHTTPBinResponse>(
536
561
  data: T;
537
562
  }
538
563
  ```
564
+ <br/>
539
565
  </details>
540
566
 
541
567
 
@@ -556,6 +582,9 @@ await sendPOST<IHTTPBinResponse>(
556
582
  ## Running the Tests
557
583
 
558
584
  ```bash
585
+ # unit and integration tests
586
+ npm run test
587
+
559
588
  # unit tests
560
589
  npm run test:unit
561
590
 
@@ -571,29 +600,4 @@ npm run test:integration
571
600
 
572
601
  ## License
573
602
 
574
- [MIT](https://choosealicense.com/licenses/mit/)
575
-
576
-
577
-
578
-
579
-
580
- <br />
581
-
582
- ## Deployment
583
-
584
- Install dependencies:
585
- ```bash
586
- npm install
587
- ```
588
-
589
-
590
- Build the library:
591
- ```bash
592
- npm start
593
- ```
594
-
595
-
596
- Publish to `npm`:
597
- ```bash
598
- npm publish
599
- ```
603
+ [MIT](https://choosealicense.com/licenses/mit/)
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ declare const send: <T>(input: IRequestInput, options?: Partial<IOptions>, retry
22
22
  * worth retrying as they could fail temporarily and prevent a view from loading.
23
23
  * @param input
24
24
  * @param options?
25
- * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying
25
+ * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying (Defaults to [3, 5])
26
26
  * @returns Promise<IRequestResponse>
27
27
  * @throws
28
28
  * - INVALID_REQUEST_URL: if the provided input URL cannot be parsed
@@ -38,7 +38,7 @@ declare const sendGET: <T>(input: IRequestInput, options?: Partial<IOptions>, re
38
38
  * Builds and sends a POST HTTP Request based on the provided input and options.
39
39
  * @param input
40
40
  * @param options?
41
- * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying
41
+ * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying. (Defaults to undefined)
42
42
  * @returns Promise<IRequestResponse>
43
43
  * @throws
44
44
  * - INVALID_REQUEST_URL: if the provided input URL cannot be parsed
@@ -54,7 +54,7 @@ declare const sendPOST: <T>(input: IRequestInput, options?: Partial<IOptions>, r
54
54
  * Builds and sends a PUT HTTP Request based on the provided input and options.
55
55
  * @param input
56
56
  * @param options?
57
- * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying
57
+ * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying. (Defaults to undefined)
58
58
  * @returns Promise<IRequestResponse>
59
59
  * @throws
60
60
  * - INVALID_REQUEST_URL: if the provided input URL cannot be parsed
@@ -70,7 +70,7 @@ declare const sendPUT: <T>(input: IRequestInput, options?: Partial<IOptions>, re
70
70
  * Builds and sends a PATCH HTTP Request based on the provided input and options.
71
71
  * @param input
72
72
  * @param options?
73
- * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying
73
+ * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying. (Defaults to undefined)
74
74
  * @returns Promise<IRequestResponse>
75
75
  * @throws
76
76
  * - INVALID_REQUEST_URL: if the provided input URL cannot be parsed
@@ -86,7 +86,7 @@ declare const sendPATCH: <T>(input: IRequestInput, options?: Partial<IOptions>,
86
86
  * Builds and sends a DELETE HTTP Request based on the provided input and options.
87
87
  * @param input
88
88
  * @param options?
89
- * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying
89
+ * @param retryDelaySchedule? - list of seconds that will be applied to the delay before retrying. (Defaults to undefined)
90
90
  * @returns Promise<IRequestResponse>
91
91
  * @throws
92
92
  * - INVALID_REQUEST_URL: if the provided input URL cannot be parsed
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{extractMessage}from"error-message-utils";import{isArrayValid,delay}from"web-utils-kit";import{buildOptions,buildRequest,extractErrorMessageFromResponseBody,extractResponseData}from"./utils/utils.js";import{validateResponse}from"./validations/validations.js";const __executeSend=async(e,t)=>{const s=buildOptions(t),r=buildRequest(e,s.requestOptions),a=await fetch(r);try{return validateResponse(r,a,s),a.redirected&&console.warn(`The request sent to '${r.url}' was redirected. Please update the implementation to avoid future redirections.`),{code:a.status,statusText:a.statusText,headers:a.headers,data:await extractResponseData(a,s.responseDataType)}}catch(e){const t=await extractErrorMessageFromResponseBody(a);if(t)throw new Error(extractMessage(e),{cause:t});throw e}},send=async(e,t,s)=>{try{return await __executeSend(e,t)}catch(r){if(extractMessage(r).includes("429")||!isArrayValid(s))throw r;return await delay(s[0]),send(e,t,s.slice(1))}},sendGET=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"GET"}},s),sendPOST=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"POST"}},s),sendPUT=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"PUT"}},s),sendPATCH=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"PATCH"}},s),sendDELETE=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"DELETE"}},s);export{send,sendGET,sendPOST,sendPUT,sendPATCH,sendDELETE};
1
+ import{extractMessage}from"error-message-utils";import{isArrayValid,delay}from"web-utils-kit";import{buildOptions,buildRequest,isRequestRetryable,extractErrorMessageFromResponseBody,extractResponseData}from"./utils/utils.js";import{validateResponse}from"./validations/validations.js";const __executeSend=async(e,t)=>{const s=buildOptions(t),r=buildRequest(e,s.requestOptions),a=await fetch(r);try{return validateResponse(r,a,s),a.redirected&&console.warn(`The request sent to '${r.url}' was redirected. Please update the implementation to avoid future redirections.`),{code:a.status,statusText:a.statusText,headers:a.headers,data:await extractResponseData(a,s.responseDataType)}}catch(e){const t=await extractErrorMessageFromResponseBody(a);if(t)throw new Error(extractMessage(e),{cause:t});throw e}},send=async(e,t,s)=>{try{return await __executeSend(e,t)}catch(r){if(!isArrayValid(s)||!isRequestRetryable(r))throw r;return await delay(s[0]),send(e,t,s.slice(1))}},sendGET=(e,t,s=[3,5])=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"GET"}},s),sendPOST=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"POST"}},s),sendPUT=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"PUT"}},s),sendPATCH=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"PATCH"}},s),sendDELETE=(e,t,s)=>send(e,{...t,requestOptions:{...t?.requestOptions,method:"DELETE"}},s);export{send,sendGET,sendPOST,sendPUT,sendPATCH,sendDELETE};
@@ -2,4 +2,4 @@ type IErrorCode = 'INVALID_REQUEST_URL' | 'INVALID_REQUEST_HEADERS' | 'INVALID_R
2
2
  declare const ERRORS: {
3
3
  [key in IErrorCode]: IErrorCode;
4
4
  };
5
- export { ERRORS, };
5
+ export { ERRORS };
@@ -10,6 +10,17 @@ import { IRequestInput, IRequestOptions, IResponseDataType, IOptions } from '../
10
10
  * - INVALID_REQUEST_OPTIONS: if the Request Instance cannot be instantiated due to the passed opts
11
11
  */
12
12
  declare const buildRequest: (input: IRequestInput, options?: Partial<IRequestOptions>) => Request;
13
+ /**
14
+ * Extracts the error message from the error object and checks if it is retryable based on the
15
+ * status code included in the message. The list of non-retryable status codes includes:
16
+ * - 401: Unauthorized
17
+ * - 403: Forbidden
18
+ * - 404: Not Found
19
+ * - 429: Too Many Requests
20
+ * @param error The error object thrown by the fetch request or the validation functions
21
+ * @returns boolean indicating whether the request is retryable or not
22
+ */
23
+ declare const isRequestRetryable: (error: unknown) => boolean;
13
24
  /**
14
25
  * Extracts the data from the Response object based on the provided data type.
15
26
  * @param res
@@ -33,4 +44,4 @@ declare const extractErrorMessageFromResponseBody: (res: Response) => Promise<st
33
44
  * @returns IOptions
34
45
  */
35
46
  declare const buildOptions: (options?: Partial<IOptions>) => IOptions;
36
- export { buildRequest, extractResponseData, extractErrorMessageFromResponseBody, buildOptions, };
47
+ export { buildRequest, isRequestRetryable, extractResponseData, extractErrorMessageFromResponseBody, buildOptions, };
@@ -1 +1 @@
1
- import{encodeError,extractMessage,isDefaultErrorMessage,isEncodedError}from"error-message-utils";import{isArrayValid,isObjectValid}from"web-utils-kit";import{ERRORS}from"../shared/errors.js";const __buildRequestInput=e=>{if(e instanceof URL)return e;try{return new URL(e)}catch(e){throw new Error(encodeError(e,ERRORS.INVALID_REQUEST_URL))}},__buildRequestHeaders=(e,r)=>{let t;if(e&&"object"==typeof e)try{t=new Headers(e)}catch(e){throw new Error(encodeError(e,ERRORS.INVALID_REQUEST_HEADERS))}else t=e instanceof Headers?e:"GET"===r?new Headers({Accept:"application/json"}):new Headers({Accept:"application/json","Content-Type":"application/json"});return t.has("Accept")||t.append("Accept","application/json"),t.has("Content-Type")||"GET"===r||t.append("Content-Type","application/json"),t},__buildRequestBody=e=>e?isObjectValid(e,!0)||isArrayValid(e,!0)?JSON.stringify(e):e:null,__buildRequestOptions=(e={})=>{const r=e.method??"GET";return{method:r,mode:e.mode??"cors",cache:e.cache??"default",credentials:e.credentials??"same-origin",headers:__buildRequestHeaders(e.headers,r),priority:e.priority??"auto",redirect:e.redirect??"follow",referrer:e.referrer??"about:client",referrerPolicy:e.referrerPolicy??"no-referrer-when-downgrade",signal:e.signal,integrity:e.integrity||"",keepalive:e.keepalive??!1,body:"GET"===r?null:__buildRequestBody(e.body)}},buildRequest=(e,r)=>{try{return new Request(__buildRequestInput(e),__buildRequestOptions(r))}catch(e){if(isEncodedError(e))throw e;throw new Error(encodeError(e,ERRORS.INVALID_REQUEST_OPTIONS))}},extractResponseData=async(e,r)=>{switch(r){case"arrayBuffer":return e.arrayBuffer();case"blob":return e.blob();case"formData":return e.formData();case"json":return e.json();case"text":return e.text();default:throw new Error(encodeError(`The provided response data type '${r}' is invalid.`,ERRORS.INVALID_RESPONSE_DTYPE))}},extractErrorMessageFromResponseBody=async e=>{try{const r=await e.json(),t=extractMessage(r);return isDefaultErrorMessage(t)?void 0:t}catch(e){return}},buildOptions=(e={})=>({requestOptions:e.requestOptions,responseDataType:e.responseDataType??"json",acceptableStatusCodes:e.acceptableStatusCodes,acceptableStatusCodesRange:e.acceptableStatusCodesRange??{min:200,max:299},skipStatusCodeValidation:e.skipStatusCodeValidation??!1});export{buildRequest,extractResponseData,extractErrorMessageFromResponseBody,buildOptions};
1
+ import{encodeError,extractMessage,isDefaultErrorMessage,isEncodedError}from"error-message-utils";import{isArrayValid,isObjectValid}from"web-utils-kit";import{ERRORS}from"../shared/errors.js";const __buildRequestInput=e=>{if(e instanceof URL)return e;try{return new URL(e)}catch(e){throw new Error(encodeError(e,ERRORS.INVALID_REQUEST_URL))}},__buildRequestHeaders=(e,r)=>{let t;if(e&&"object"==typeof e)try{t=new Headers(e)}catch(e){throw new Error(encodeError(e,ERRORS.INVALID_REQUEST_HEADERS))}else t=e instanceof Headers?e:"GET"===r?new Headers({Accept:"application/json"}):new Headers({Accept:"application/json","Content-Type":"application/json"});return t.has("Accept")||t.append("Accept","application/json"),t.has("Content-Type")||"GET"===r||t.append("Content-Type","application/json"),t},__buildRequestBody=e=>e?isObjectValid(e,!0)||isArrayValid(e,!0)?JSON.stringify(e):e:null,__buildRequestOptions=(e={})=>{const r=e.method??"GET";return{method:r,mode:e.mode??"cors",cache:e.cache??"default",credentials:e.credentials??"same-origin",headers:__buildRequestHeaders(e.headers,r),priority:e.priority??"auto",redirect:e.redirect??"follow",referrer:e.referrer??"about:client",referrerPolicy:e.referrerPolicy??"no-referrer-when-downgrade",signal:e.signal,integrity:e.integrity||"",keepalive:e.keepalive??!1,body:"GET"===r?null:__buildRequestBody(e.body)}},buildRequest=(e,r)=>{try{return new Request(__buildRequestInput(e),__buildRequestOptions(r))}catch(e){if(isEncodedError(e))throw e;throw new Error(encodeError(e,ERRORS.INVALID_REQUEST_OPTIONS))}},isRequestRetryable=e=>{const r=extractMessage(e);return!(r.includes("401")||r.includes("403")||r.includes("404")||r.includes("429"))},extractResponseData=async(e,r)=>{switch(r){case"arrayBuffer":return e.arrayBuffer();case"blob":return e.blob();case"formData":return e.formData();case"json":return e.json();case"text":return e.text();default:throw new Error(encodeError(`The provided response data type '${r}' is invalid.`,ERRORS.INVALID_RESPONSE_DTYPE))}},extractErrorMessageFromResponseBody=async e=>{try{const r=await e.json(),t=extractMessage(r);return isDefaultErrorMessage(t)?void 0:t}catch(e){return}},buildOptions=(e={})=>({requestOptions:e.requestOptions,responseDataType:e.responseDataType??"json",acceptableStatusCodes:e.acceptableStatusCodes,acceptableStatusCodesRange:e.acceptableStatusCodesRange??{min:200,max:299},skipStatusCodeValidation:e.skipStatusCodeValidation??!1});export{buildRequest,isRequestRetryable,extractResponseData,extractErrorMessageFromResponseBody,buildOptions};
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "fetch-request-browser",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "The fetch-request-browser package makes working with external APIs simple and efficient. This intuitive wrapper leverages the power of the Fetch API, providing a clean and concise interface for your API interactions.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "type": "module",
8
8
  "scripts": {
9
- "start": "ts-lib-builder --tsconfig=tsconfig.build.json",
10
- "test": "echo \"Error: tests are executed with npm run test:(integration|unit)\" && exit 1",
9
+ "build": "ts-lib-builder --tsconfig=tsconfig.build.json",
10
+ "test": "npm run test:unit && npm run test:integration",
11
11
  "test:integration": "vitest run --config vitest.test-integration.config.ts",
12
12
  "test:unit": "vitest run --config vitest.test-unit.config.ts",
13
13
  "watch-test:integration": "vitest --config vitest.test-integration.config.ts",
@@ -33,16 +33,18 @@
33
33
  },
34
34
  "homepage": "https://github.com/jesusgraterol/fetch-request-browser#readme",
35
35
  "devDependencies": {
36
- "@types/node": "^20.17.17",
37
- "@typescript-eslint/eslint-plugin": "^7.18.0",
38
- "@typescript-eslint/parser": "^7.18.0",
39
- "eslint-config-airbnb-typescript": "^18.0.0",
40
- "ts-lib-builder": "^1.0.5",
41
- "typescript": "^5.7.3",
42
- "vitest": "^1.6.1"
36
+ "@types/node": "20.17.17",
37
+ "@typescript-eslint/eslint-plugin": "7.18.0",
38
+ "@typescript-eslint/parser": "7.18.0",
39
+ "eslint-config-airbnb-typescript": "18.0.0",
40
+ "eslint-config-prettier": "10.1.8",
41
+ "prettier": "3.6.2",
42
+ "ts-lib-builder": "1.0.8",
43
+ "typescript": "5.7.3",
44
+ "vitest": "3.2.4"
43
45
  },
44
46
  "dependencies": {
45
- "error-message-utils": "^1.1.3",
46
- "web-utils-kit": "^1.0.5"
47
+ "error-message-utils": "1.1.6",
48
+ "web-utils-kit": "1.0.16"
47
49
  }
48
50
  }