fetch-request-browser 1.0.5 → 1.0.7

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,130 +12,522 @@ 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 install -S fetch-request-browser
16
16
  ```
17
17
 
18
+ ### Examples
18
19
 
19
-
20
-
21
-
22
- <br />
23
-
24
- ## Usage
20
+ Send a `GET` request that will retry (up to 3 times) on failure to [HTTPBin](https://httpbin.org/):
25
21
 
26
22
  ```typescript
27
- import { send } from 'fetch-request-browser';
23
+ import { sendGET } from 'fetch-request-browser';
28
24
 
29
- await send(
30
- 'https://httpbin.org/get',
25
+ await sendGET<IHTTPBinResponse>(
26
+ 'https://httpbin.org/get?someUid=5',
31
27
  {
32
28
  requestOptions: {
33
- method: 'GET'
34
- }
29
+ credentials: 'include',
30
+ },
31
+ acceptableStatusCodes: [200, 201],
35
32
  },
36
33
  [3, 5, 10]
37
34
  );
38
35
  // {
39
36
  // code: 200,
40
37
  // headers: Headers {
41
- // date: 'Tue, 04 Jun 2024 18:52:29 GMT',
38
+ // date: 'Fri, 06 Dec 2024 14:14:12 GMT',
42
39
  // 'content-type': 'application/json',
43
- // 'content-length': '407',
40
+ // 'content-length': '399',
44
41
  // connection: 'keep-alive',
45
42
  // server: 'gunicorn/19.9.0',
46
43
  // 'access-control-allow-origin': '*',
47
44
  // 'access-control-allow-credentials': 'true'
48
45
  // },
49
46
  // data: {
50
- // args: {},
47
+ // args: { someUid: '5' },
51
48
  // headers: {
52
49
  // Accept: 'application/json',
53
50
  // 'Accept-Encoding': 'br, gzip, deflate',
54
51
  // 'Accept-Language': '*',
55
- // 'Content-Type': 'application/json',
56
52
  // Host: 'httpbin.org',
57
53
  // 'Sec-Fetch-Mode': 'cors',
58
54
  // 'User-Agent': 'node',
59
- // 'X-Amzn-Trace-Id': '...'
55
+ // 'X-Amzn-Trace-Id': 'Root=1-675306b4-175937342b1b6ffa6ddbaaee'
60
56
  // },
61
- // origin: '...',
62
- // url: 'https://httpbin.org/get'
57
+ // origin: '136.144.19.103',
58
+ // url: 'https://httpbin.org/get?someUid=5'
63
59
  // }
64
60
  // }
65
61
  ```
66
62
 
63
+ Send a `POST` request that will retry (up to 3 times) on failure to [HTTPBin](https://httpbin.org/):
67
64
 
65
+ ```typescript
66
+ import { sendGET } from 'fetch-request-browser';
67
+
68
+ await sendPOST<IHTTPBinResponse>(
69
+ 'https://httpbin.org/post?id=1',
70
+ {
71
+ requestOptions: {
72
+ body: {
73
+ someKey: 'Hello',
74
+ someNumber: 123456,
75
+ },
76
+ credentials: 'include',
77
+ },
78
+ acceptableStatusCodes: [200, 201],
79
+ },
80
+ [3, 5, 10]
81
+ );
82
+ // {
83
+ // code: 200,
84
+ // headers: Headers {
85
+ // date: 'Fri, 06 Dec 2024 12:57:25 GMT',
86
+ // 'content-type': 'application/json',
87
+ // 'content-length': '619',
88
+ // connection: 'keep-alive',
89
+ // server: 'gunicorn/19.9.0',
90
+ // 'access-control-allow-origin': '*',
91
+ // 'access-control-allow-credentials': 'true'
92
+ // },
93
+ // data: {
94
+ // args: { id: '1' },
95
+ // data: '{"someKey":"Hello","someNumber":123456}',
96
+ // files: {},
97
+ // form: {},
98
+ // headers: {
99
+ // Accept: 'application/json',
100
+ // 'Accept-Encoding': 'br, gzip, deflate',
101
+ // 'Accept-Language': '*',
102
+ // 'Content-Length': '39',
103
+ // 'Content-Type': 'application/json',
104
+ // Host: 'httpbin.org',
105
+ // 'Sec-Fetch-Mode': 'cors',
106
+ // 'User-Agent': 'node',
107
+ // 'X-Amzn-Trace-Id': 'Root=1-6752f4b5-76a61b597284afb62df479eb'
108
+ // },
109
+ // json: { someKey: 'Hello', someNumber: 123456 },
110
+ // origin: '136.144.19.233',
111
+ // url: 'https://httpbin.org/post?id=1'
112
+ // }
113
+ // }
114
+ ```
68
115
 
69
116
 
70
117
 
71
- <br/>
72
-
73
- ## API
74
118
 
75
- Build and send an HTTP Request (any method):
76
119
 
77
- ```typescript
78
- send(
79
- input: IRequestInput,
80
- options?: Partial<IOptions>,
81
- retryDelaySchedule?: number[],
82
- ): Promise<IRequestResponse>
83
- ```
120
+ <br/>
84
121
 
85
- <br />
122
+ ## API Reference
123
+
124
+ <details>
125
+ <summary><code>send</code></summary>
126
+
127
+ Builds and sends an HTTP Request based on the provided input and options.
128
+ ```typescript
129
+ await send<IHTTPBinResponse>(
130
+ 'https://httpbin.org/get?foo=hey&bar=123', {
131
+ requestOptions: { method: 'GET' }
132
+ }
133
+ );
134
+ // {
135
+ // code: 200,
136
+ // headers: Headers {
137
+ // date: 'Fri, 06 Dec 2024 13:05:20 GMT',
138
+ // 'content-type': 'application/json',
139
+ // 'content-length': '422',
140
+ // connection: 'keep-alive',
141
+ // server: 'gunicorn/19.9.0',
142
+ // 'access-control-allow-origin': '*',
143
+ // 'access-control-allow-credentials': 'true'
144
+ // },
145
+ // data: {
146
+ // args: { bar: '123', foo: 'hey' },
147
+ // headers: {
148
+ // Accept: 'application/json',
149
+ // 'Accept-Encoding': 'br, gzip, deflate',
150
+ // 'Accept-Language': '*',
151
+ // Host: 'httpbin.org',
152
+ // 'Sec-Fetch-Mode': 'cors',
153
+ // 'User-Agent': 'node',
154
+ // 'X-Amzn-Trace-Id': 'Root=1-6752f690-43ddfac50ee723b532cf3cf3'
155
+ // },
156
+ // origin: '136.144.19.106',
157
+ // url: 'https://httpbin.org/get?foo=hey&bar=123'
158
+ // }
159
+ // }
160
+ ```
161
+ </details>
162
+
163
+ <details>
164
+ <summary><code>sendGET</code></summary>
165
+
166
+ Builds and sends a `GET` HTTP Request based on the provided input and options.
167
+ ```typescript
168
+ await sendGET<IHTTPBinResponse>('https://httpbin.org/get?foo=hey&bar=123');
169
+ // {
170
+ // code: 200,
171
+ // headers: Headers {
172
+ // date: 'Fri, 06 Dec 2024 13:05:20 GMT',
173
+ // 'content-type': 'application/json',
174
+ // 'content-length': '422',
175
+ // connection: 'keep-alive',
176
+ // server: 'gunicorn/19.9.0',
177
+ // 'access-control-allow-origin': '*',
178
+ // 'access-control-allow-credentials': 'true'
179
+ // },
180
+ // data: {
181
+ // args: { bar: '123', foo: 'hey' },
182
+ // headers: {
183
+ // Accept: 'application/json',
184
+ // 'Accept-Encoding': 'br, gzip, deflate',
185
+ // 'Accept-Language': '*',
186
+ // Host: 'httpbin.org',
187
+ // 'Sec-Fetch-Mode': 'cors',
188
+ // 'User-Agent': 'node',
189
+ // 'X-Amzn-Trace-Id': 'Root=1-6752f690-43ddfac50ee723b532cf3cf3'
190
+ // },
191
+ // origin: '136.144.19.106',
192
+ // url: 'https://httpbin.org/get?foo=hey&bar=123'
193
+ // }
194
+ // }
195
+ ```
196
+ </details>
197
+
198
+ <details>
199
+ <summary><code>sendPOST</code></summary>
200
+
201
+ Builds and sends a `POST` HTTP Request based on the provided input and options.
202
+ ```typescript
203
+ await sendPOST<IHTTPBinResponse>(
204
+ 'https://httpbin.org/post',
205
+ {
206
+ requestOptions: {
207
+ body: {
208
+ someKey: 'Hello',
209
+ someNumber: 123456,
210
+ },
211
+ },
212
+ },
213
+ );
214
+ // {
215
+ // code: 200,
216
+ // headers: Headers {
217
+ // date: 'Fri, 06 Dec 2024 13:13:18 GMT',
218
+ // 'content-type': 'application/json',
219
+ // 'content-length': '596',
220
+ // connection: 'keep-alive',
221
+ // server: 'gunicorn/19.9.0',
222
+ // 'access-control-allow-origin': '*',
223
+ // 'access-control-allow-credentials': 'true'
224
+ // },
225
+ // data: {
226
+ // args: {},
227
+ // data: '{"someKey":"Hello","someNumber":123456}',
228
+ // files: {},
229
+ // form: {},
230
+ // headers: {
231
+ // Accept: 'application/json',
232
+ // 'Accept-Encoding': 'br, gzip, deflate',
233
+ // 'Accept-Language': '*',
234
+ // 'Content-Length': '39',
235
+ // 'Content-Type': 'application/json',
236
+ // Host: 'httpbin.org',
237
+ // 'Sec-Fetch-Mode': 'cors',
238
+ // 'User-Agent': 'node',
239
+ // 'X-Amzn-Trace-Id': 'Root=1-6752f86e-366f8cb71596c46374885670'
240
+ // },
241
+ // json: { someKey: 'Hello', someNumber: 123456 },
242
+ // origin: '136.144.19.99',
243
+ // url: 'https://httpbin.org/post'
244
+ // }
245
+ // }
246
+ ```
247
+ </details>
248
+
249
+ <details>
250
+ <summary><code>sendPUT</code></summary>
251
+
252
+ Builds and sends a `PUT` HTTP Request based on the provided input and options.
253
+ ```typescript
254
+ await sendPUT<IHTTPBinResponse>(
255
+ 'https://httpbin.org/put',
256
+ {
257
+ requestOptions: {
258
+ body: {
259
+ someKey: 'Hello',
260
+ someNumber: 123456,
261
+ },
262
+ },
263
+ },
264
+ );
265
+ // {
266
+ // code: 200,
267
+ // headers: Headers {
268
+ // date: 'Fri, 06 Dec 2024 13:19:07 GMT',
269
+ // 'content-type': 'application/json',
270
+ // 'content-length': '596',
271
+ // connection: 'keep-alive',
272
+ // server: 'gunicorn/19.9.0',
273
+ // 'access-control-allow-origin': '*',
274
+ // 'access-control-allow-credentials': 'true'
275
+ // },
276
+ // data: {
277
+ // args: {},
278
+ // data: '{"someKey":"Hello","someNumber":123456}',
279
+ // files: {},
280
+ // form: {},
281
+ // headers: {
282
+ // Accept: 'application/json',
283
+ // 'Accept-Encoding': 'br, gzip, deflate',
284
+ // 'Accept-Language': '*',
285
+ // 'Content-Length': '39',
286
+ // 'Content-Type': 'application/json',
287
+ // Host: 'httpbin.org',
288
+ // 'Sec-Fetch-Mode': 'cors',
289
+ // 'User-Agent': 'node',
290
+ // 'X-Amzn-Trace-Id': 'Root=1-6752f9cb-4633cbc111fccdc020c15081'
291
+ // },
292
+ // json: { someKey: 'Hello', someNumber: 123456 },
293
+ // origin: '136.144.19.122',
294
+ // url: 'https://httpbin.org/put'
295
+ // }
296
+ // }
297
+ ```
298
+ </details>
299
+
300
+ <details>
301
+ <summary><code>sendPATCH</code></summary>
302
+
303
+ Builds and sends a `PATCH` HTTP Request based on the provided input and options.
304
+ ```typescript
305
+ await sendPATCH<IHTTPBinResponse>(
306
+ 'https://httpbin.org/patch',
307
+ {
308
+ requestOptions: {
309
+ body: {
310
+ someKey: 'Hello',
311
+ someNumber: 123456,
312
+ },
313
+ },
314
+ },
315
+ );
316
+ // {
317
+ // code: 200,
318
+ // headers: Headers {
319
+ // date: 'Fri, 06 Dec 2024 13:22:54 GMT',
320
+ // 'content-type': 'application/json',
321
+ // 'content-length': '597',
322
+ // connection: 'keep-alive',
323
+ // server: 'gunicorn/19.9.0',
324
+ // 'access-control-allow-origin': '*',
325
+ // 'access-control-allow-credentials': 'true'
326
+ // },
327
+ // data: {
328
+ // args: {},
329
+ // data: '{"someKey":"Hello","someNumber":123456}',
330
+ // files: {},
331
+ // form: {},
332
+ // headers: {
333
+ // Accept: 'application/json',
334
+ // 'Accept-Encoding': 'br, gzip, deflate',
335
+ // 'Accept-Language': '*',
336
+ // 'Content-Length': '39',
337
+ // 'Content-Type': 'application/json',
338
+ // Host: 'httpbin.org',
339
+ // 'Sec-Fetch-Mode': 'cors',
340
+ // 'User-Agent': 'node',
341
+ // 'X-Amzn-Trace-Id': 'Root=1-6752faae-7da3d0d33f55d85f1f563abb'
342
+ // },
343
+ // json: { someKey: 'Hello', someNumber: 123456 },
344
+ // origin: '136.144.19.93',
345
+ // url: 'https://httpbin.org/patch'
346
+ // }
347
+ // }
348
+ ```
349
+ </details>
350
+
351
+ <details>
352
+ <summary><code>sendDELETE</code></summary>
353
+
354
+ Builds and sends a `DELETE` HTTP Request based on the provided input and options.
355
+ ```typescript
356
+ await sendDELETE<IHTTPBinResponse>('https://httpbin.org/delete?id=1');
357
+ // {
358
+ // code: 200,
359
+ // headers: Headers {
360
+ // date: 'Fri, 06 Dec 2024 13:25:41 GMT',
361
+ // 'content-type': 'application/json',
362
+ // 'content-length': '496',
363
+ // connection: 'keep-alive',
364
+ // server: 'gunicorn/19.9.0',
365
+ // 'access-control-allow-origin': '*',
366
+ // 'access-control-allow-credentials': 'true'
367
+ // },
368
+ // data: {
369
+ // args: { id: '1' },
370
+ // data: '',
371
+ // files: {},
372
+ // form: {},
373
+ // headers: {
374
+ // Accept: 'application/json',
375
+ // 'Accept-Encoding': 'br, gzip, deflate',
376
+ // 'Accept-Language': '*',
377
+ // 'Content-Type': 'application/json',
378
+ // Host: 'httpbin.org',
379
+ // 'Sec-Fetch-Mode': 'cors',
380
+ // 'User-Agent': 'node',
381
+ // 'X-Amzn-Trace-Id': 'Root=1-6752fb55-62da6f1d3348e8a55af75ae3'
382
+ // },
383
+ // json: null,
384
+ // origin: '136.144.19.240',
385
+ // url: 'https://httpbin.org/delete?id=1'
386
+ // }
387
+ // }
388
+ ```
389
+ </details>
86
390
 
87
- Build and send a `GET` HTTP Request:
88
- ```typescript
89
- sendGET(
90
- input: IRequestInput,
91
- options?: Partial<IOptions>,
92
- retryDelaySchedule?: number[],
93
- ): Promise<IRequestResponse>
94
- ```
95
391
 
96
- <br />
97
392
 
98
- Build and send a `POST` HTTP Request:
99
- ```typescript
100
- sendPOST(
101
- input: IRequestInput,
102
- options?: Partial<IOptions>,
103
- retryDelaySchedule?: number[],
104
- ): Promise<IRequestResponse>
105
- ```
106
393
 
107
- <br />
108
394
 
109
- Build and send a `PUT` HTTP Request:
110
- ```typescript
111
- sendPUT(
112
- input: IRequestInput,
113
- options?: Partial<IOptions>,
114
- retryDelaySchedule?: number[],
115
- ): Promise<IRequestResponse>
116
- ```
117
395
 
118
396
  <br />
119
397
 
120
- Build and send a `PATCH` HTTP Request:
121
- ```typescript
122
- sendPATCH(
123
- input: IRequestInput,
124
- options?: Partial<IOptions>,
125
- retryDelaySchedule?: number[],
126
- ): Promise<IRequestResponse>
127
- ```
398
+ ## Types
399
+
400
+ <details>
401
+ <summary><code>IRequestInput</code></summary>
402
+
403
+ The URL of the request's target.
404
+ ```typescript
405
+ type IRequestInput = string | URL;
406
+ ```
407
+ </details>
408
+
409
+ <details>
410
+ <summary><code>IRequestMethod</code></summary>
411
+
412
+ The HTTP Methods supported by this library. To make use of a different one, pass the method name directly in the request options.
413
+ ```typescript
414
+ type IRequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
415
+ ```
416
+ </details>
417
+
418
+ <details>
419
+ <summary><code>RequestInit</code></summary>
420
+
421
+ 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.
422
+ ```typescript
423
+ interface RequestInit {
424
+ /** A BodyInit object or null to set request's body. */
425
+ body?: BodyInit | null;
426
+ /** A string indicating how the request will interact with the browser's cache to set request's cache. */
427
+ cache?: RequestCache;
428
+ /** A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials. */
429
+ credentials?: RequestCredentials;
430
+ /** A Headers object, an object literal, or an array of two-item arrays to set request's headers. */
431
+ headers?: HeadersInit;
432
+ /** A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */
433
+ integrity?: string;
434
+ /** A boolean to set request's keepalive. */
435
+ keepalive?: boolean;
436
+ /** A string to set request's method. */
437
+ method?: string;
438
+ /** A string to indicate whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. */
439
+ mode?: RequestMode;
440
+ priority?: RequestPriority;
441
+ /** A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. */
442
+ redirect?: RequestRedirect;
443
+ /** A string whose value is a same-origin URL, "about:client", or the empty string, to set request's referrer. */
444
+ referrer?: string;
445
+ /** A referrer policy to set request's referrerPolicy. */
446
+ referrerPolicy?: ReferrerPolicy;
447
+ /** An AbortSignal to set request's signal. */
448
+ signal?: AbortSignal | null;
449
+ /** Can only be null. Used to disassociate request from any Window. */
450
+ window?: null;
451
+ }
452
+ ```
453
+ </details>
454
+
455
+ <details>
456
+ <summary><code>IRequestOptions</code></summary>
457
+
458
+ The options that can be applied when sending a Fetch Request.
459
+ 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.
460
+ ```typescript
461
+ interface IRequestOptions extends Omit<RequestInit, 'body'> {
462
+ method: IRequestMethod; // this lib only makes use of these methods
463
+ body: BodyInit | Record<string, unknown> | Array<unknown> | null;
464
+ }
465
+
466
+ interface IProcessedRequestOptions extends RequestInit {
467
+ method: IRequestMethod;
468
+ }
469
+ ```
470
+ </details>
471
+
472
+ <details>
473
+ <summary><code>IResponseDataType</code></summary>
474
+
475
+ The type of data that will be extracted from the HTTP Response body.
476
+ ```typescript
477
+ type IResponseDataType = 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'text';
478
+ ```
479
+ </details>
480
+
481
+ <details>
482
+ <summary><code>IOptions</code></summary>
483
+
484
+ The options object that can be passed and used for any request.
485
+ ```typescript
486
+ interface IOptions {
487
+ // the options that will be used to build the request
488
+ requestOptions?: Partial<IRequestOptions>;
489
+
490
+ // the expected data type that should be extracted from the response
491
+ responseDataType: IResponseDataType;
492
+
493
+ /**
494
+ * Response Status Codes
495
+ * The request's response can be validated by providing a list of acceptable codes or a range
496
+ * object. Keep in mind that if the acceptableStatusCodes array is provided, it will only perform
497
+ * that validation and ignore the acceptableStatusCodesRange.
498
+ */
499
+
500
+ // the list of status codes that won't throw an error
501
+ acceptableStatusCodes?: number[];
502
+
503
+ // the range of codes that are considered to be acceptable. Defaults to: { min: 200, max: 299 }
504
+ acceptableStatusCodesRange: { min: number, max: number };
505
+
506
+ // if enabled, it will not validate the status code from the response object
507
+ skipStatusCodeValidation: boolean;
508
+ }
509
+ ```
510
+ </details>
511
+
512
+ <details>
513
+ <summary><code>IRequestResponse<T></code></summary>
514
+
515
+ The object containing the result of the Request.
516
+ ```typescript
517
+ interface IRequestResponse<T> {
518
+ // the HTTP status code extracted from the Response
519
+ code: number;
520
+
521
+ // the Response's Headers. Useful as some service providers attach important info in the headers
522
+ headers: Headers;
523
+
524
+ // the data extracted from the Response Instance
525
+ data: T;
526
+ }
527
+ ```
528
+ </details>
128
529
 
129
- <br />
130
530
 
131
- Build and send a `DELETE` HTTP Request:
132
- ```typescript
133
- sendDELETE(
134
- input: IRequestInput,
135
- options?: Partial<IOptions>,
136
- retryDelaySchedule?: number[],
137
- ): Promise<IRequestResponse>
138
- ```
139
531
 
140
532
 
141
533
 
@@ -153,11 +545,11 @@ sendDELETE(
153
545
  ## Running the Tests
154
546
 
155
547
  ```bash
156
- # Unit Tests
157
- $ npm run test:unit
548
+ # unit tests
549
+ npm run test:unit
158
550
 
159
- # Integration Tests
160
- $ npm run test:integration
551
+ # integration tests
552
+ npm run test:integration
161
553
  ```
162
554
 
163
555
 
@@ -174,44 +566,23 @@ $ npm run test:integration
174
566
 
175
567
 
176
568
 
177
- <br />
178
-
179
- ## Acknowledgments
180
-
181
- - [MDN](https://developer.mozilla.org/en-US/)
182
- - [web.dev](https://web.dev/)
183
-
184
-
185
-
186
-
187
-
188
- <br />
189
-
190
- ## @TODOS
191
-
192
- - [ ] Improve the docs
193
-
194
-
195
-
196
-
197
-
198
569
  <br />
199
570
 
200
571
  ## Deployment
201
572
 
202
573
  Install dependencies:
203
574
  ```bash
204
- $ npm install
575
+ npm install
205
576
  ```
206
577
 
207
578
 
208
579
  Build the library:
209
580
  ```bash
210
- $ npm start
581
+ npm start
211
582
  ```
212
583
 
213
584
 
214
585
  Publish to `npm`:
215
586
  ```bash
216
- $ npm publish
587
+ npm publish
217
588
  ```
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ import { IRequestInput, IRequestMethod, IRequestOptions, IResponseDataType, IOpt
14
14
  * - CONTENT_TYPE_MISSMATCH: if the Content-Type Headers don't match
15
15
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
16
16
  */
17
- declare const send: (input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse>;
17
+ declare const send: <T>(input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse<T>>;
18
18
  /**
19
19
  * Builds and sends a GET HTTP Request based on the provided input and options.
20
20
  * IMPORTANT: The browser environment can be highly unreliable as the user can physically move
@@ -33,7 +33,7 @@ declare const send: (input: IRequestInput, options?: Partial<IOptions>, retryDel
33
33
  * - CONTENT_TYPE_MISSMATCH: if the Content-Type Headers don't match
34
34
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
35
35
  */
36
- declare const sendGET: (input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse>;
36
+ declare const sendGET: <T>(input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse<T>>;
37
37
  /**
38
38
  * Builds and sends a POST HTTP Request based on the provided input and options.
39
39
  * @param input
@@ -49,7 +49,7 @@ declare const sendGET: (input: IRequestInput, options?: Partial<IOptions>, retry
49
49
  * - CONTENT_TYPE_MISSMATCH: if the Content-Type Headers don't match
50
50
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
51
51
  */
52
- declare const sendPOST: (input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse>;
52
+ declare const sendPOST: <T>(input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse<T>>;
53
53
  /**
54
54
  * Builds and sends a PUT HTTP Request based on the provided input and options.
55
55
  * @param input
@@ -65,7 +65,7 @@ declare const sendPOST: (input: IRequestInput, options?: Partial<IOptions>, retr
65
65
  * - CONTENT_TYPE_MISSMATCH: if the Content-Type Headers don't match
66
66
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
67
67
  */
68
- declare const sendPUT: (input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse>;
68
+ declare const sendPUT: <T>(input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse<T>>;
69
69
  /**
70
70
  * Builds and sends a PATCH HTTP Request based on the provided input and options.
71
71
  * @param input
@@ -81,7 +81,7 @@ declare const sendPUT: (input: IRequestInput, options?: Partial<IOptions>, retry
81
81
  * - CONTENT_TYPE_MISSMATCH: if the Content-Type Headers don't match
82
82
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
83
83
  */
84
- declare const sendPATCH: (input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse>;
84
+ declare const sendPATCH: <T>(input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse<T>>;
85
85
  /**
86
86
  * Builds and sends a DELETE HTTP Request based on the provided input and options.
87
87
  * @param input
@@ -97,5 +97,5 @@ declare const sendPATCH: (input: IRequestInput, options?: Partial<IOptions>, ret
97
97
  * - CONTENT_TYPE_MISSMATCH: if the Content-Type Headers don't match
98
98
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
99
99
  */
100
- declare const sendDELETE: (input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse>;
101
- export { IRequestInput, IRequestMethod, IRequestOptions, IResponseDataType, IOptions, IRequestResponse, send, sendGET, sendPOST, sendPUT, sendPATCH, sendDELETE, };
100
+ declare const sendDELETE: <T>(input: IRequestInput, options?: Partial<IOptions>, retryDelaySchedule?: number[]) => Promise<IRequestResponse<T>>;
101
+ export { type IRequestInput, type IRequestMethod, type IRequestOptions, type IResponseDataType, type IOptions, type IRequestResponse, send, sendGET, sendPOST, sendPUT, sendPATCH, sendDELETE, };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{extractMessage}from"error-message-utils";import{buildOptions,buildRequest,extractResponseData,delay}from"./utils/utils.js";import{validateResponse}from"./validations/validations.js";const __executeSend=async(e,s)=>{const t=buildOptions(s),n=buildRequest(e,t.requestOptions),r=await fetch(n);return validateResponse(n,r,t),r.redirected&&console.warn(`The request sent to '${n.url}' was redirected. Please update the implementation to avoid future redirections.`),{code:r.status,headers:r.headers,data:await extractResponseData(r,t.responseDataType)}},send=async(e,s,t)=>{try{return await __executeSend(e,s)}catch(n){if(extractMessage(n).includes("429")||!Array.isArray(t)||0===t.length)throw n;return await delay(t[0]),send(e,s,t.slice(1))}},sendGET=async(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"GET"}},t),sendPOST=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"POST"}},t),sendPUT=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"PUT"}},t),sendPATCH=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"PATCH"}},t),sendDELETE=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"DELETE"}},t);export{send,sendGET,sendPOST,sendPUT,sendPATCH,sendDELETE};
1
+ import{extractMessage}from"error-message-utils";import{isArrayValid,delay}from"web-utils-kit";import{buildOptions,buildRequest,extractResponseData}from"./utils/utils.js";import{validateResponse}from"./validations/validations.js";const __executeSend=async(e,s)=>{const t=buildOptions(s),n=buildRequest(e,t.requestOptions),r=await fetch(n);return validateResponse(n,r,t),r.redirected&&console.warn(`The request sent to '${n.url}' was redirected. Please update the implementation to avoid future redirections.`),{code:r.status,headers:r.headers,data:await extractResponseData(r,t.responseDataType)}},send=async(e,s,t)=>{try{return await __executeSend(e,s)}catch(n){if(extractMessage(n).includes("429")||!isArrayValid(t))throw n;return await delay(t[0]),send(e,s,t.slice(1))}},sendGET=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"GET"}},t),sendPOST=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"POST"}},t),sendPUT=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"PUT"}},t),sendPATCH=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"PATCH"}},t),sendDELETE=(e,s,t)=>send(e,{...s,requestOptions:{...s?.requestOptions,method:"DELETE"}},t);export{send,sendGET,sendPOST,sendPUT,sendPATCH,sendDELETE};
@@ -1,10 +1,5 @@
1
- declare enum ERRORS {
2
- INVALID_REQUEST_URL = "INVALID_REQUEST_URL",
3
- INVALID_REQUEST_HEADERS = "INVALID_REQUEST_HEADERS",
4
- INVALID_REQUEST_OPTIONS = "INVALID_REQUEST_OPTIONS",
5
- INVALID_RESPONSE_DTYPE = "INVALID_RESPONSE_DTYPE",
6
- UNEXPECTED_RESPONSE_STATUS_CODE = "UNEXPECTED_RESPONSE_STATUS_CODE",
7
- INVALID_RESPONSE_CONTENT_TYPE = "INVALID_RESPONSE_CONTENT_TYPE",
8
- CONTENT_TYPE_MISSMATCH = "CONTENT_TYPE_MISSMATCH"
9
- }
1
+ type IErrorCode = 'INVALID_REQUEST_URL' | 'INVALID_REQUEST_HEADERS' | 'INVALID_REQUEST_OPTIONS' | 'INVALID_RESPONSE_DTYPE' | 'UNEXPECTED_RESPONSE_STATUS_CODE' | 'INVALID_RESPONSE_CONTENT_TYPE' | 'CONTENT_TYPE_MISSMATCH';
2
+ declare const ERRORS: {
3
+ [key in IErrorCode]: IErrorCode;
4
+ };
10
5
  export { ERRORS, };
@@ -1 +1 @@
1
- var ERRORS;!function(E){E.INVALID_REQUEST_URL="INVALID_REQUEST_URL",E.INVALID_REQUEST_HEADERS="INVALID_REQUEST_HEADERS",E.INVALID_REQUEST_OPTIONS="INVALID_REQUEST_OPTIONS",E.INVALID_RESPONSE_DTYPE="INVALID_RESPONSE_DTYPE",E.UNEXPECTED_RESPONSE_STATUS_CODE="UNEXPECTED_RESPONSE_STATUS_CODE",E.INVALID_RESPONSE_CONTENT_TYPE="INVALID_RESPONSE_CONTENT_TYPE",E.CONTENT_TYPE_MISSMATCH="CONTENT_TYPE_MISSMATCH"}(ERRORS||(ERRORS={}));export{ERRORS};
1
+ const ERRORS={INVALID_REQUEST_URL:"INVALID_REQUEST_URL",INVALID_REQUEST_HEADERS:"INVALID_REQUEST_HEADERS",INVALID_REQUEST_OPTIONS:"INVALID_REQUEST_OPTIONS",INVALID_RESPONSE_DTYPE:"INVALID_RESPONSE_DTYPE",UNEXPECTED_RESPONSE_STATUS_CODE:"UNEXPECTED_RESPONSE_STATUS_CODE",INVALID_RESPONSE_CONTENT_TYPE:"INVALID_RESPONSE_CONTENT_TYPE",CONTENT_TYPE_MISSMATCH:"CONTENT_TYPE_MISSMATCH"};export{ERRORS};
@@ -8,11 +8,14 @@ type IRequestInput = string | URL;
8
8
  * The options that can be applied when sending a Fetch Request.
9
9
  * IMPORTANT: the reason RequestInit is extended is because in the original type, the body property
10
10
  * does not accept plain objects. Even though this makes sense, the body is processed in the
11
- * utilities so the Request's body is always instantiated with a string.
11
+ * utilities so the Request's body is always going to have a valid type.
12
12
  */
13
- interface IRequestOptions extends RequestInit {
13
+ interface IRequestOptions extends Omit<RequestInit, 'body'> {
14
+ method: IRequestMethod;
15
+ body: BodyInit | Record<string, unknown> | Array<unknown> | null;
16
+ }
17
+ interface IProcessedRequestOptions extends RequestInit {
14
18
  method: IRequestMethod;
15
- body: any;
16
19
  }
17
20
  /**
18
21
  * Request Method
@@ -29,7 +32,6 @@ type IResponseDataType = 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'text';
29
32
  * Response Data
30
33
  * The format of the data that can be extracted from the Response object.
31
34
  */
32
- type IResponseData<T> = T extends 'arrayBuffer' ? ArrayBuffer : T extends 'blob' ? Blob : T extends 'formData' ? FormData : T extends 'json' ? any : T extends 'text' ? string : never;
33
35
  /**
34
36
  * Options
35
37
  * The options object that can be passed and used for any request.
@@ -54,9 +56,9 @@ interface IOptions {
54
56
  * Request Response
55
57
  * The object containing the result of the Request.
56
58
  */
57
- interface IRequestResponse {
59
+ interface IRequestResponse<T> {
58
60
  code: number;
59
61
  headers: Headers;
60
- data: any;
62
+ data: T;
61
63
  }
62
- export type { IRequestInput, IRequestOptions, IRequestMethod, IResponseDataType, IResponseData, IOptions, IRequestResponse, };
64
+ export type { IRequestInput, IRequestOptions, IProcessedRequestOptions, IRequestMethod, IResponseDataType, IOptions, IRequestResponse, };
@@ -1,4 +1,4 @@
1
- import { IRequestInput, IResponseDataType, IResponseData, IRequestOptions, IOptions } from '../shared/types.js';
1
+ import { IRequestInput, IRequestOptions, IResponseDataType, IOptions } from '../shared/types.js';
2
2
  /**
3
3
  * Builds the Request Instance based on given input and options.
4
4
  * @param input
@@ -18,17 +18,11 @@ declare const buildRequest: (input: IRequestInput, options?: Partial<IRequestOpt
18
18
  * @throws
19
19
  * - INVALID_RESPONSE_DTYPE: if the data type is not supported by the Response Instance
20
20
  */
21
- declare const extractResponseData: <T extends IResponseDataType>(res: Response, dType: T) => Promise<IResponseData<T>>;
21
+ declare const extractResponseData: <T>(res: Response, dType: IResponseDataType) => Promise<T>;
22
22
  /**
23
23
  * Builds the main options object based on given args (if any).
24
24
  * @param options
25
25
  * @returns IOptions
26
26
  */
27
27
  declare const buildOptions: (options?: Partial<IOptions>) => IOptions;
28
- /**
29
- * Creates an asynchronous delay that resolves once the provided seconds have passed.
30
- * @param seconds
31
- * @returns Promise<void>
32
- */
33
- declare const delay: (seconds: number) => Promise<void>;
34
- export { buildRequest, extractResponseData, buildOptions, delay, };
28
+ export { buildRequest, extractResponseData, buildOptions, };
@@ -1 +1 @@
1
- import{encodeError,isEncodedError}from"error-message-utils";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?"object"==typeof e?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))}},buildOptions=(e={})=>({requestOptions:e.requestOptions,responseDataType:e.responseDataType??"json",acceptableStatusCodes:e.acceptableStatusCodes,acceptableStatusCodesRange:e.acceptableStatusCodesRange??{min:200,max:299},skipStatusCodeValidation:e.skipStatusCodeValidation??!1}),delay=e=>new Promise((r=>{setTimeout(r,1e3*e)}));export{buildRequest,extractResponseData,buildOptions,delay};
1
+ import{encodeError,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))}},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,buildOptions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fetch-request-browser",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
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",
@@ -33,15 +33,16 @@
33
33
  },
34
34
  "homepage": "https://github.com/jesusgraterol/fetch-request-browser#readme",
35
35
  "devDependencies": {
36
- "@types/node": "^20.14.12",
37
- "@typescript-eslint/eslint-plugin": "^7.17.0",
38
- "@typescript-eslint/parser": "^7.17.0",
36
+ "@types/node": "^20.17.9",
37
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
38
+ "@typescript-eslint/parser": "^7.18.0",
39
39
  "eslint-config-airbnb-typescript": "^18.0.0",
40
- "ts-lib-builder": "^1.0.3",
41
- "typescript": "^5.5.4",
40
+ "ts-lib-builder": "^1.0.5",
41
+ "typescript": "^5.7.2",
42
42
  "vitest": "^1.6.0"
43
43
  },
44
44
  "dependencies": {
45
- "error-message-utils": "^1.1.1"
45
+ "error-message-utils": "^1.1.2",
46
+ "web-utils-kit": "^1.0.3"
46
47
  }
47
48
  }