@superhero/http-request 4.0.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.
Files changed (4) hide show
  1. package/README.md +351 -0
  2. package/index.js +704 -0
  3. package/index.test.js +555 -0
  4. package/package.json +27 -0
package/README.md ADDED
@@ -0,0 +1,351 @@
1
+ # HTTP-Request
2
+
3
+ An HTTP client for Node.js supporting HTTP/1.1 and HTTP/2.0, with support for retries, timeouts, and streaming.
4
+
5
+ ## Features
6
+
7
+ - **Protocol Support**: HTTP/1.1 and HTTP/2.0.
8
+ - **HTTP Methods**: Supports all standard methods—GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE.
9
+ - **Retries**: Configurable retry mechanism for requests.
10
+ - **Timeouts**: Set request timeouts to prevent hanging requests.
11
+ - **Streaming**: Stream request bodies and responses (upstream and downstream).
12
+ - **Data Handling**: Automatically handles JSON and URL-encoded form data.
13
+ - **Customizable**: Configure headers, body, query parameters, and more.
14
+
15
+ ## Installation
16
+
17
+ Install via npm:
18
+
19
+ ```bash
20
+ npm install @superhero/http-request
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Importing the Module
26
+
27
+ ```javascript
28
+ import Request from '@superhero/http-request'
29
+ ```
30
+
31
+ ### Creating a Request Instance
32
+
33
+ ```javascript
34
+ const request = new Request({
35
+ base : 'https://example.com',
36
+ headers : { 'Content-Type': 'application/json' },
37
+ timeout : 5e3, // 5 seconds
38
+ retry : 3, // Retry up to 3 times
39
+ retryDelay : 200 // 200ms delay between retries
40
+ })
41
+ ```
42
+
43
+ ### Making Requests
44
+
45
+ Use the methods corresponding to HTTP verbs:
46
+
47
+ - `get(options)`
48
+ - `post(options)`
49
+ - `put(options)`
50
+ - `patch(options)`
51
+ - `delete(options)`
52
+ - `head(options)`
53
+ - `options(options)`
54
+ - `trace(options)`
55
+
56
+ Each method accepts an `options` object.
57
+
58
+ #### Example: GET Request
59
+
60
+ ```javascript
61
+ const response = await request.get('/users')
62
+
63
+ console.log(response.status) // HTTP status code
64
+ console.log(response.headers) // Response headers
65
+ console.log(response.body) // Parsed response body
66
+ ```
67
+
68
+ #### Example: POST Request with JSON Body
69
+
70
+ ```javascript
71
+ const response = await request.post({
72
+ url : '/users',
73
+ body : { name: 'John Doe', email: 'john@example.com' }
74
+ })
75
+
76
+ console.log(response.status)
77
+ console.log(response.body)
78
+ ```
79
+
80
+ #### Example: PUT Request with Form Data
81
+
82
+ ```javascript
83
+ const response = await request.put({
84
+ url : '/users/123',
85
+ headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
86
+ body : { name: 'Jane Doe', email: 'jane@example.com' }
87
+ })
88
+
89
+ console.log(response.status)
90
+ console.log(response.body)
91
+ ```
92
+
93
+ ### Handling Errors
94
+
95
+ Errors are thrown with specific error codes for easier handling:
96
+
97
+ - `E_HTTP_REQUEST_CLIENT_ERROR`
98
+ - `E_HTTP_REQUEST_CLIENT_TIMEOUT`
99
+ - `E_HTTP_REQUEST_DOWNSTREAM_ERROR`
100
+ - `E_HTTP_REQUEST_INVALID_RESPONSE_BODY_FORMAT`
101
+ - `E_HTTP_REQUEST_INVALID_RESPONSE_STATUS`
102
+
103
+ Example:
104
+
105
+ ```javascript
106
+ try {
107
+ const response = await request.get({ url: '/data' })
108
+ }
109
+ catch (error) {
110
+ console.error('Request failed:', error.message, error.code)
111
+ }
112
+ ```
113
+
114
+ ### Configuring Retries and Timeouts
115
+
116
+ ```javascript
117
+ const response = await request.get({
118
+ url: '/unstable-endpoint',
119
+ timeout: 3000, // 3 seconds timeout
120
+ retry: 5, // Retry up to 5 times
121
+ retryDelay: 500, // 500ms delay between retries
122
+ retryOnClientTimeout: true // Retry if client times out
123
+ })
124
+ ```
125
+
126
+ ### Streaming Data
127
+
128
+ #### Streaming Request Body (Upstream)
129
+
130
+ Stream data to the server using the `upstream` option with a readable stream.
131
+
132
+ ```javascript
133
+ import { Readable } from 'node:stream'
134
+
135
+ const upstream = Readable.from(['streaming ', 'data ', 'to ', 'server'])
136
+
137
+ const response = await request.post({
138
+ url: '/upload',
139
+ upstream
140
+ })
141
+ ```
142
+
143
+ #### Streaming Response Body (Downstream)
144
+
145
+ Stream the response data from the server using the `downstream` option with a writable stream.
146
+
147
+ ```javascript
148
+ import { createWriteStream } from 'node:fs'
149
+
150
+ const downstream = createWriteStream('output.txt')
151
+
152
+ const response = await request.get({
153
+ url: '/download',
154
+ downstream
155
+ })
156
+
157
+ downstream.on('finish', () => {
158
+ console.log('Download completed.')
159
+ })
160
+ ```
161
+
162
+ ### Using HTTP/2
163
+
164
+ Establish a connection for HTTP/2 requests.
165
+
166
+ ```javascript
167
+ await request.connect('http://api.example.com')
168
+
169
+ // Now you can make HTTP/2 requests
170
+ const response = await request.get({ url: '/users' })
171
+
172
+ // Close the connection when done
173
+ await request.close()
174
+ ```
175
+
176
+ ## API Reference
177
+
178
+ ### Class: Request
179
+
180
+ #### Constructor
181
+
182
+ ```javascript
183
+ new Request(config)
184
+ ```
185
+
186
+ - `config`: An object containing default request configurations.
187
+
188
+ #### Methods
189
+
190
+ - **connect(authority, [options])**
191
+ - Connects to an HTTP/2 server.
192
+ - `authority`: The URL to connect to.
193
+ - `options`: Optional connection options.
194
+
195
+ - **close()**
196
+ - Closes the HTTP/2 client connection.
197
+
198
+ - **get(options)**
199
+ - Makes a GET request.
200
+
201
+ - **post(options)**
202
+ - Makes a POST request.
203
+
204
+ - **put(options)**
205
+ - Makes a PUT request.
206
+
207
+ - **patch(options)**
208
+ - Makes a PATCH request.
209
+
210
+ - **delete(options)**
211
+ - Makes a DELETE request.
212
+
213
+ - **head(options)**
214
+ - Makes a HEAD request.
215
+
216
+ - **options(options)**
217
+ - Makes an OPTIONS request.
218
+
219
+ - **trace(options)**
220
+ - Makes a TRACE request.
221
+
222
+ #### Request Options
223
+
224
+ - **url**: The endpoint URL (relative to `base` if provided).
225
+ - **base**: The base URL for resolving relative URLs.
226
+ - **headers**: An object containing request headers.
227
+ - **body** or **data**: The request payload (object or string).
228
+ - **method**: HTTP method (overrides method implied by the function used).
229
+ - **timeout**: Request timeout in milliseconds.
230
+ - **retry**: Number of retry attempts on failure.
231
+ - **retryDelay**: Delay between retries in milliseconds.
232
+ - **retryOnStatus**: Array of HTTP status codes to trigger a retry.
233
+ - **retryOnClientTimeout**: Retry on client timeout (`true` or `false`).
234
+ - **retryOnDownstreamError**: Retry on downstream errors (`true` or `false`).
235
+ - **retryOnInvalidResponseBodyFormat**: Retry if response body format is invalid (`true` or `false`).
236
+ - **retryOnErrorResponseStatus**: Retry on error HTTP statuses (`true` or `false`).
237
+ - **doNotThrowOnErrorStatus**: Do not throw on error statuses (`true` or `false`).
238
+ - **doNotThrowOnRedirectStatus**: Do not throw on redirect statuses (`true` or `false`).
239
+ - **upstream**: A `Readable` stream to pipe the request body from.
240
+ - **downstream**: A `Writable` stream to pipe the response body to.
241
+
242
+ #### Response Object
243
+
244
+ - **status**: HTTP status code of the response.
245
+ - **headers**: Response headers as an object.
246
+ - **body**: Parsed response body. If the response is JSON, it's parsed automatically. If `downstream` is used, `body` is omitted.
247
+
248
+ ## Testing
249
+
250
+ The test suite uses Node.js's built-in `node:test` module.
251
+
252
+ ### Running the Tests
253
+
254
+ To run the tests, execute:
255
+
256
+ ```bash
257
+ node test.js
258
+ ```
259
+
260
+ ### Test Coverage
261
+
262
+ ```
263
+ ▶ @superhero/http-request
264
+ ▶ HTTP 1.1
265
+ ▶ Request using method
266
+ ✔ POST (29.927617ms)
267
+ ✔ PUT (6.608225ms)
268
+ ✔ PATCH (4.07807ms)
269
+ ✔ GET (4.255941ms)
270
+ ✔ DELETE (5.305515ms)
271
+ ✔ HEAD (4.096928ms)
272
+ ✔ OPTIONS (4.635634ms)
273
+ ✔ TRACE (4.071535ms)
274
+ ✔ Request using method (64.83487ms)
275
+
276
+ ✔ Request using the URL as the option parameter (8.577185ms)
277
+ ✔ Request using a string body (5.060509ms)
278
+ ✔ Request using a custom header (3.345092ms)
279
+ ✔ Normalizes headers and body (2.763181ms)
280
+ ✔ Can pipe upstream body through the request from a readable stream (6.058912ms)
281
+ ✔ Can pipe downstream response from the request to a writable stream (5.560773ms)
282
+
283
+ ▶ Tests that require an altered server response
284
+ ✔ Supports request timeout (106.042009ms)
285
+ ✔ Rejects invalid JSON response accurately (4.167691ms)
286
+ ✔ Retry on client error (214.183201ms)
287
+ ✔ Retry on client timeout (311.841398ms)
288
+ ✔ Retry on invalid response body format (208.378113ms)
289
+
290
+ ▶ Retry on response status
291
+ ✔ Retry on status: 503 - should succeed after re-attempts (209.880754ms)
292
+ ✔ Retry on status: 503 - should reject after to few re-attempts (108.7312ms)
293
+ ✔ Retry on status: 500 - should reject on first attempt (4.106091ms)
294
+
295
+ ▶ Retry on error response status
296
+ ✔ Should succeed after re-attempts (212.3066ms)
297
+ ✔ Should succeed after re-attempts when "doNotThrowOnErrorStatus" (8.122609ms)
298
+ ✔ Retry on error response status (222.080598ms)
299
+ ✔ Retry on response status (547.205892ms)
300
+ ✔ Tests that require an altered server response (1392.469482ms)
301
+ ✔ HTTP 1.1 (1489.71029ms)
302
+
303
+ ▶ HTTP 2.0
304
+ ▶ Request using method
305
+ ✔ POST (24.172115ms)
306
+ ✔ PUT (4.569734ms)
307
+ ✔ PATCH (5.478934ms)
308
+ ✔ GET (3.347633ms)
309
+ ✔ DELETE (4.18065ms)
310
+ ✔ HEAD (2.557823ms)
311
+ ✔ OPTIONS (3.031275ms)
312
+ ✔ TRACE (4.541577ms)
313
+ ✔ Request using method (52.666782ms)
314
+
315
+ ✔ Request using the URL as the option parameter (3.139841ms)
316
+ ✔ Request using a string body (3.152696ms)
317
+ ✔ Request using a custom header (2.364444ms)
318
+ ✔ Normalizes headers and body (3.156592ms)
319
+ ✔ Can pipe upstream body through the request from a readable stream (4.870264ms)
320
+ ✔ Can pipe downstream response from the request to a writable stream (2.96681ms)
321
+
322
+ ▶ Tests that require an altered server response
323
+ ✔ Retry on connection error (212.816865ms)
324
+ ✔ Supports request timeout (108.664584ms)
325
+ ✔ Tests that require an altered server response (322.005974ms)
326
+ ✔ HTTP 2.0 (394.95823ms)
327
+ ✔ @superhero/http-request (1885.245212ms)
328
+
329
+ tests 42
330
+ suites 7
331
+ pass 42
332
+
333
+ ------------------------------------------------------------------------
334
+ file | line % | branch % | funcs % | uncovered lines
335
+ ------------------------------------------------------------------------
336
+ index.js | 97.16 | 92.45 | 95.12 | 487-496 524-526 662-668
337
+ index.test.js | 100.00 | 97.67 | 100.00 |
338
+ ------------------------------------------------------------------------
339
+ all files | 98.41 | 94.79 | 98.10 |
340
+ ------------------------------------------------------------------------
341
+ ```
342
+
343
+ ---
344
+
345
+ ## License
346
+ This project is licensed under the MIT License.
347
+
348
+ ---
349
+
350
+ ## Contributing
351
+ Feel free to submit issues or pull requests for improvements or additional features.