got 8.3.2 → 9.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.
- package/package.json +17 -42
- package/readme.md +222 -54
- package/source/as-promise.js +112 -0
- package/source/as-stream.js +115 -0
- package/source/create.js +56 -0
- package/source/deep-freeze.js +12 -0
- package/{errors.js → source/errors.js} +9 -0
- package/source/get-body-size.js +40 -0
- package/source/get-response.js +60 -0
- package/source/index.js +49 -0
- package/source/is-form-data.js +4 -0
- package/source/is-retry-on-network-error-allowed.js +17 -0
- package/source/merge.js +32 -0
- package/source/normalize-arguments.js +230 -0
- package/source/progress.js +71 -0
- package/source/request-as-event-emitter.js +185 -0
- package/source/timed-out.js +160 -0
- package/source/url-to-options.js +25 -0
- package/index.js +0 -675
package/package.json
CHANGED
|
@@ -1,36 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "got",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "Simplified HTTP requests",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/got",
|
|
7
|
-
"
|
|
8
|
-
{
|
|
9
|
-
"name": "Sindre Sorhus",
|
|
10
|
-
"email": "sindresorhus@gmail.com",
|
|
11
|
-
"url": "sindresorhus.com"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"name": "Vsevolod Strukchinsky",
|
|
15
|
-
"email": "floatdrop@gmail.com",
|
|
16
|
-
"url": "github.com/floatdrop"
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"name": "Alexander Tesfamichael",
|
|
20
|
-
"email": "alex.tesfamichael@gmail.com",
|
|
21
|
-
"url": "alextes.me"
|
|
22
|
-
}
|
|
23
|
-
],
|
|
7
|
+
"main": "source",
|
|
24
8
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
9
|
+
"node": ">=8.6"
|
|
26
10
|
},
|
|
27
11
|
"scripts": {
|
|
28
12
|
"test": "xo && nyc ava",
|
|
29
13
|
"coveralls": "nyc report --reporter=text-lcov | coveralls"
|
|
30
14
|
},
|
|
31
15
|
"files": [
|
|
32
|
-
"
|
|
33
|
-
"errors.js"
|
|
16
|
+
"source"
|
|
34
17
|
],
|
|
35
18
|
"keywords": [
|
|
36
19
|
"http",
|
|
@@ -51,39 +34,31 @@
|
|
|
51
34
|
"electron"
|
|
52
35
|
],
|
|
53
36
|
"dependencies": {
|
|
54
|
-
"@sindresorhus/is": "^0.
|
|
55
|
-
"cacheable-request": "^
|
|
37
|
+
"@sindresorhus/is": "^0.11.0",
|
|
38
|
+
"cacheable-request": "^4.0.1",
|
|
56
39
|
"decompress-response": "^3.3.0",
|
|
57
40
|
"duplexer3": "^0.1.4",
|
|
58
41
|
"get-stream": "^3.0.0",
|
|
59
|
-
"into-stream": "^3.1.0",
|
|
60
|
-
"is-retry-allowed": "^1.1.0",
|
|
61
|
-
"isurl": "^1.0.0-alpha5",
|
|
62
|
-
"lowercase-keys": "^1.0.0",
|
|
63
42
|
"mimic-response": "^1.0.0",
|
|
64
|
-
"p-cancelable": "^0.
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"safe-buffer": "^5.1.1",
|
|
68
|
-
"timed-out": "^4.0.1",
|
|
69
|
-
"url-parse-lax": "^3.0.0",
|
|
70
|
-
"url-to-options": "^1.0.1"
|
|
43
|
+
"p-cancelable": "^0.5.0",
|
|
44
|
+
"to-readable-stream": "^1.0.0",
|
|
45
|
+
"url-parse-lax": "^3.0.0"
|
|
71
46
|
},
|
|
72
47
|
"devDependencies": {
|
|
73
|
-
"ava": "^0.
|
|
48
|
+
"ava": "^1.0.0-beta.6",
|
|
74
49
|
"coveralls": "^3.0.0",
|
|
50
|
+
"delay": "^3.0.0",
|
|
75
51
|
"form-data": "^2.1.1",
|
|
76
|
-
"get-port": "^
|
|
77
|
-
"nyc": "^
|
|
78
|
-
"p-event": "^1.
|
|
52
|
+
"get-port": "^4.0.0",
|
|
53
|
+
"nyc": "^12.0.2",
|
|
54
|
+
"p-event": "^2.1.0",
|
|
79
55
|
"pem": "^1.4.4",
|
|
80
|
-
"proxyquire": "^
|
|
81
|
-
"sinon": "^
|
|
56
|
+
"proxyquire": "^2.0.1",
|
|
57
|
+
"sinon": "^6.1.0",
|
|
82
58
|
"slow-stream": "0.0.4",
|
|
83
59
|
"tempfile": "^2.0.0",
|
|
84
60
|
"tempy": "^0.2.1",
|
|
85
|
-
"
|
|
86
|
-
"xo": "^0.20.0"
|
|
61
|
+
"xo": "^0.21.1"
|
|
87
62
|
},
|
|
88
63
|
"ava": {
|
|
89
64
|
"concurrency": 4
|
package/readme.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
> Simplified HTTP requests
|
|
15
15
|
|
|
16
|
-
[](https://travis-ci.org/sindresorhus/got) [](https://coveralls.io/github/sindresorhus/got?branch=master) [](https://npmjs.com/got)
|
|
16
|
+
[](https://travis-ci.org/sindresorhus/got) [](https://ci.appveyor.com/project/sindresorhus/got/branch/master) [](https://coveralls.io/github/sindresorhus/got?branch=master) [](https://npmjs.com/got)
|
|
17
17
|
|
|
18
18
|
A nicer interface to the built-in [`http`](http://nodejs.org/api/http.html) module.
|
|
19
19
|
|
|
@@ -26,7 +26,7 @@ Created because [`request`](https://github.com/request/request) is bloated *(sev
|
|
|
26
26
|
- [Request cancelation](#aborting-the-request)
|
|
27
27
|
- [RFC compliant caching](#cache-adapters)
|
|
28
28
|
- [Follows redirects](#followredirect)
|
|
29
|
-
- [Retries on
|
|
29
|
+
- [Retries on failure](#retry)
|
|
30
30
|
- [Progress events](#onuploadprogress-progress)
|
|
31
31
|
- [Handles gzip/deflate](#decompress)
|
|
32
32
|
- [Timeout handling](#timeout)
|
|
@@ -34,6 +34,7 @@ Created because [`request`](https://github.com/request/request) is bloated *(sev
|
|
|
34
34
|
- [JSON mode](#json)
|
|
35
35
|
- [WHATWG URL support](#url)
|
|
36
36
|
- [Electron support](#useelectronnet)
|
|
37
|
+
- [Instances with custom defaults](#instances)
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
## Install
|
|
@@ -93,7 +94,7 @@ The response will also have a `fromCache` property set with a boolean value.
|
|
|
93
94
|
|
|
94
95
|
Type: `string` `Object`
|
|
95
96
|
|
|
96
|
-
The URL to request as simple string, a [`
|
|
97
|
+
The URL to request as simple string, a [`https.request` options](https://nodejs.org/api/https.html#https_https_request_options_callback), or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).
|
|
97
98
|
|
|
98
99
|
Properties from `options` will override properties in the parsed `url`.
|
|
99
100
|
|
|
@@ -103,7 +104,27 @@ If no protocol is specified, it will default to `https`.
|
|
|
103
104
|
|
|
104
105
|
Type: `Object`
|
|
105
106
|
|
|
106
|
-
Any of the [`
|
|
107
|
+
Any of the [`https.request`](https://nodejs.org/api/https.html#https_https_request_options_callback) options.
|
|
108
|
+
|
|
109
|
+
###### baseUrl
|
|
110
|
+
|
|
111
|
+
Type: `string` `Object`
|
|
112
|
+
|
|
113
|
+
When specified, `url` will be prepended by `baseUrl`.<br>
|
|
114
|
+
If you specify an absolute URL, it will skip the `baseUrl`.
|
|
115
|
+
|
|
116
|
+
Very useful when used with `got.extend()` to create niche-specific `got` instances.
|
|
117
|
+
|
|
118
|
+
Can be a string or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).
|
|
119
|
+
|
|
120
|
+
###### headers
|
|
121
|
+
|
|
122
|
+
Type: `Object`<br>
|
|
123
|
+
Default: `{}`
|
|
124
|
+
|
|
125
|
+
Request headers.
|
|
126
|
+
|
|
127
|
+
Existing headers will be overwritten. Headers set to `null` will be omitted.
|
|
107
128
|
|
|
108
129
|
###### stream
|
|
109
130
|
|
|
@@ -114,15 +135,15 @@ Returns a `Stream` instead of a `Promise`. This is equivalent to calling `got.st
|
|
|
114
135
|
|
|
115
136
|
###### body
|
|
116
137
|
|
|
117
|
-
Type: `string` `Buffer` `stream.Readable`
|
|
138
|
+
Type: `string` `Buffer` `stream.Readable` [`form-data` instance](https://github.com/form-data/form-data)
|
|
118
139
|
|
|
119
|
-
*
|
|
140
|
+
*If you provide this option, `got.stream()` will be read-only.*
|
|
120
141
|
|
|
121
142
|
Body that will be sent with a `POST` request.
|
|
122
143
|
|
|
123
144
|
If present in `options` and `options.method` is not set, `options.method` will be set to `POST`.
|
|
124
145
|
|
|
125
|
-
|
|
146
|
+
The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / `fs.createReadStream` instance / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`.
|
|
126
147
|
|
|
127
148
|
###### encoding
|
|
128
149
|
|
|
@@ -136,18 +157,18 @@ Default: `'utf8'`
|
|
|
136
157
|
Type: `boolean`<br>
|
|
137
158
|
Default: `false`
|
|
138
159
|
|
|
139
|
-
*
|
|
160
|
+
*If you provide this option, `got.stream()` will be read-only.*
|
|
140
161
|
|
|
141
162
|
If set to `true` and `Content-Type` header is not set, it will be set to `application/x-www-form-urlencoded`.
|
|
142
163
|
|
|
143
|
-
`body` must be a plain object
|
|
164
|
+
`body` must be a plain object. It will be converted to a query string using [`(new URLSearchParams(object)).toString()`](https://nodejs.org/api/url.html#url_constructor_new_urlsearchparams_obj).
|
|
144
165
|
|
|
145
166
|
###### json
|
|
146
167
|
|
|
147
168
|
Type: `boolean`<br>
|
|
148
169
|
Default: `false`
|
|
149
170
|
|
|
150
|
-
*
|
|
171
|
+
*If you use `got.stream()`, this option will be ignored.*
|
|
151
172
|
|
|
152
173
|
If set to `true` and `Content-Type` header is not set, it will be set to `application/json`.
|
|
153
174
|
|
|
@@ -165,20 +186,42 @@ Query string object that will be added to the request URL. This will override th
|
|
|
165
186
|
|
|
166
187
|
Type: `number` `Object`
|
|
167
188
|
|
|
168
|
-
Milliseconds to wait for the server to end the response before aborting request with `
|
|
189
|
+
Milliseconds to wait for the server to end the response before aborting request with [`got.TimeoutError`](#gottimeouterror) error (a.k.a. `request` property). By default there's no timeout.
|
|
169
190
|
|
|
170
|
-
This also accepts an object with
|
|
191
|
+
This also accepts an `object` with the following fields to constrain the duration of each phase of the request lifecycle:
|
|
171
192
|
|
|
172
|
-
|
|
193
|
+
- `lookup` starts when a socket is assigned and ends when the hostname has been resolved. Does not apply when using a Unix domain socket.
|
|
194
|
+
- `connect` starts when `lookup` completes (or when the socket is assigned if lookup does not apply to the request) and ends when the socket is connected.
|
|
195
|
+
- `secureConnect` starts when `connect` completes and ends when the handshaking process completes (HTTPS only).
|
|
196
|
+
- `socket` starts when the socket is connected. See [request.setTimeout](https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback).
|
|
197
|
+
- `response` starts when the request has been written to the socket and ends when the response headers are received.
|
|
198
|
+
- `send` starts when the socket is connected and ends with the request has been written to the socket.
|
|
199
|
+
- `request` starts when the request is initiated and ends when the response's end event fires.
|
|
173
200
|
|
|
174
|
-
|
|
175
|
-
Default: `2`
|
|
201
|
+
###### retry
|
|
176
202
|
|
|
177
|
-
|
|
203
|
+
Type: `number` `Object`<br>
|
|
204
|
+
Default:
|
|
205
|
+
- retries: `2`
|
|
206
|
+
- methods: `GET` `PUT` `HEAD` `DELETE` `OPTIONS` `TRACE`
|
|
207
|
+
- statusCodes: [`408`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) [`413`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413) [`429`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) [`502`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502) [`503`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) [`504`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504)
|
|
208
|
+
- maxRetryAfter: `undefined`
|
|
178
209
|
|
|
179
|
-
|
|
210
|
+
Object representing `retries`, `methods`, `statusCodes` and `maxRetryAfter` fields for time until retry, allowed methods, allowed status codes and maximum [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) time.
|
|
180
211
|
|
|
181
|
-
|
|
212
|
+
If `maxRetryAfter` is set to `undefined`, it will use `options.timeout`.<br>
|
|
213
|
+
If [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header is greater than `maxRetryAfter`, it will cancel the request.
|
|
214
|
+
|
|
215
|
+
Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 0).
|
|
216
|
+
|
|
217
|
+
Option `retries` can be a `number`, but also accepts a `function` with `retry` and `error` arguments. Function must return delay in milliseconds (`0` return value cancels retry).
|
|
218
|
+
|
|
219
|
+
**Note:** It retries only on the specified methods, status codes, and on these network errors:
|
|
220
|
+
- `ETIMEDOUT`: One of the [timeout](#timeout) limits was reached.
|
|
221
|
+
- `ECONNRESET`: Connection was forcibly closed by a peer.
|
|
222
|
+
- `EADDRINUSE`: Could not bind to any free port.
|
|
223
|
+
- `ECONNREFUSED`: Connection was refused by the server.
|
|
224
|
+
- `EPIPE`: The remote side of the stream being written has been closed.
|
|
182
225
|
|
|
183
226
|
###### followRedirect
|
|
184
227
|
|
|
@@ -211,7 +254,7 @@ Default: `false`
|
|
|
211
254
|
Type: `boolean`<br>
|
|
212
255
|
Default: `false`
|
|
213
256
|
|
|
214
|
-
When used in Electron, Got will use [`electron.net`](https://electronjs.org/docs/api/net/) instead of the Node.js `http` module. According to the Electron docs, it should be fully compatible, but it's not entirely. See [#
|
|
257
|
+
When used in Electron, Got will use [`electron.net`](https://electronjs.org/docs/api/net/) instead of the Node.js `http` module. According to the Electron docs, it should be fully compatible, but it's not entirely. See [#443](https://github.com/sindresorhus/got/issues/443) and [#461](https://github.com/sindresorhus/got/issues/461).
|
|
215
258
|
|
|
216
259
|
###### throwHttpErrors
|
|
217
260
|
|
|
@@ -222,10 +265,32 @@ Determines if a `got.HTTPError` is thrown for error responses (non-2xx status co
|
|
|
222
265
|
|
|
223
266
|
If this is disabled, requests that encounter an error status code will be resolved with the `response` instead of throwing. This may be useful if you are checking for resource availability and are expecting error responses.
|
|
224
267
|
|
|
268
|
+
###### hooks
|
|
269
|
+
|
|
270
|
+
Type: `Object<string, Array<Function>>`<br>
|
|
271
|
+
Default: `{ beforeRequest: [] }`
|
|
272
|
+
|
|
273
|
+
Hooks allow modifications during the request lifecycle. Hook functions may be async and are run serially.
|
|
274
|
+
|
|
275
|
+
###### hooks.beforeRequest
|
|
276
|
+
|
|
277
|
+
Type: `Array<Function>`<br>
|
|
278
|
+
Default: `[]`
|
|
279
|
+
|
|
280
|
+
Called with the normalized request options. Got will make no further changes to the request before it is sent. This is especially useful in conjunction with [`got.extend()`](#instances) and [`got.create()`](advanced-creation.md) when you want to create an API client that uses HMAC-signing.
|
|
281
|
+
|
|
282
|
+
See the [AWS section](#aws) for an example.
|
|
283
|
+
|
|
284
|
+
**Note**: Modifying the `body` is not recommended because the `content-length` header has already been computed and assigned.
|
|
285
|
+
|
|
225
286
|
#### Streams
|
|
226
287
|
|
|
288
|
+
**Note**: Progress events, redirect events and request/response events can also be used with promises.
|
|
289
|
+
|
|
227
290
|
#### got.stream(url, [options])
|
|
228
291
|
|
|
292
|
+
Sets `options.stream` to `true`.
|
|
293
|
+
|
|
229
294
|
`stream` method will return Duplex stream with additional events:
|
|
230
295
|
|
|
231
296
|
##### .on('request', request)
|
|
@@ -262,8 +327,6 @@ Progress events for uploading (sending request) and downloading (receiving respo
|
|
|
262
327
|
|
|
263
328
|
If it's not possible to retrieve the body size (can happen when streaming), `total` will be `null`.
|
|
264
329
|
|
|
265
|
-
**Note**: Progress events can also be used with promises.
|
|
266
|
-
|
|
267
330
|
```js
|
|
268
331
|
(async () => {
|
|
269
332
|
const response = await got('sindresorhus.com')
|
|
@@ -291,6 +354,76 @@ If it's not possible to retrieve the body size (can happen when streaming), `tot
|
|
|
291
354
|
|
|
292
355
|
Sets `options.method` to the method name and makes a request.
|
|
293
356
|
|
|
357
|
+
### Instances
|
|
358
|
+
|
|
359
|
+
#### got.extend([options])
|
|
360
|
+
|
|
361
|
+
Configure a new `got` instance with default `options`. `options` are merged with the parent instance's `defaults.options` using [`got.mergeOptions`](#gotmergeoptionsparentoptions-newoptions).
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
```js
|
|
365
|
+
const client = got.extend({
|
|
366
|
+
baseUrl: 'https://example.com',
|
|
367
|
+
headers: {
|
|
368
|
+
'x-unicorn': 'rainbow'
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
client.get('/demo');
|
|
373
|
+
|
|
374
|
+
/* HTTP Request =>
|
|
375
|
+
* GET /demo HTTP/1.1
|
|
376
|
+
* Host: example.com
|
|
377
|
+
* x-unicorn: rainbow
|
|
378
|
+
*/
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
```js
|
|
382
|
+
(async () => {
|
|
383
|
+
const client = got.extend({
|
|
384
|
+
baseUrl: 'httpbin.org',
|
|
385
|
+
headers: {
|
|
386
|
+
'x-foo': 'bar'
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
const {headers} = (await client.get('/headers', {json: true})).body;
|
|
390
|
+
//=> headers['x-foo'] === 'bar'
|
|
391
|
+
|
|
392
|
+
const jsonClient = client.extend({
|
|
393
|
+
json: true,
|
|
394
|
+
headers: {
|
|
395
|
+
'x-baz': 'qux'
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
const {headers: headers2} = (await jsonClient.get('/headers')).body;
|
|
399
|
+
//=> headers2['x-foo'] === 'bar'
|
|
400
|
+
//=> headers2['x-baz'] === 'qux'
|
|
401
|
+
})();
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
*Need more control over the behavior of Got? Check out the [`got.create()`](advanced-creation.md).*
|
|
405
|
+
|
|
406
|
+
#### got.mergeOptions(parentOptions, newOptions)
|
|
407
|
+
|
|
408
|
+
Extends parent options. Avoid using [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals) as it doesn't work recursively:
|
|
409
|
+
|
|
410
|
+
```js
|
|
411
|
+
const a = {headers: {cat: 'meow', wolf: ['bark', 'wrrr']}};
|
|
412
|
+
const b = {headers: {cow: 'moo', wolf: ['auuu']}};
|
|
413
|
+
|
|
414
|
+
{...a, ...b} // => {headers: {cow: 'moo', wolf: ['auuu']}}
|
|
415
|
+
got.mergeOptions(a, b) // => {headers: {cat: 'meow', cow: 'moo', wolf: ['auuu']}}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Options are deeply merged to a new object. The value of each key is determined as follows:
|
|
419
|
+
|
|
420
|
+
- If the new property is set to `undefined`, it keeps the old one.
|
|
421
|
+
- If the parent property is an instance of `URL` and the new value is a `string` or `URL`, a new URL instance is created: [`new URL(new, parent)`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#Syntax).
|
|
422
|
+
- If the new property is a plain `Object`:
|
|
423
|
+
- If the parent property is a plain `Object` too, both values are merged recursively into a new `Object`.
|
|
424
|
+
- Otherwise, only the new value is deeply cloned.
|
|
425
|
+
- If the new property is an `Array`, it overwrites the old one with a deep clone of the new property.
|
|
426
|
+
- Otherwise, the new value is assigned to the key.
|
|
294
427
|
|
|
295
428
|
## Errors
|
|
296
429
|
|
|
@@ -330,6 +463,9 @@ When given an unsupported protocol.
|
|
|
330
463
|
|
|
331
464
|
When the request is aborted with `.cancel()`.
|
|
332
465
|
|
|
466
|
+
#### got.TimeoutError
|
|
467
|
+
|
|
468
|
+
When the request is aborted due to a [timeout](#timeout)
|
|
333
469
|
|
|
334
470
|
## Aborting the request
|
|
335
471
|
|
|
@@ -421,7 +557,7 @@ You can use the [`tunnel`](https://github.com/koichik/node-tunnel) module with t
|
|
|
421
557
|
|
|
422
558
|
```js
|
|
423
559
|
const got = require('got');
|
|
424
|
-
const tunnel = require('tunnel');
|
|
560
|
+
const tunnel = require('tunnel-agent');
|
|
425
561
|
|
|
426
562
|
got('sindresorhus.com', {
|
|
427
563
|
agent: tunnel.httpOverHttp({
|
|
@@ -461,6 +597,15 @@ got('google.com', {
|
|
|
461
597
|
cookie: cookie.serialize('foo', 'bar')
|
|
462
598
|
}
|
|
463
599
|
});
|
|
600
|
+
|
|
601
|
+
got('google.com', {
|
|
602
|
+
headers: {
|
|
603
|
+
cookie: [
|
|
604
|
+
cookie.serialize('foo', 'bar'),
|
|
605
|
+
cookie.serialize('fizz', 'buzz')
|
|
606
|
+
].join(';')
|
|
607
|
+
}
|
|
608
|
+
});
|
|
464
609
|
```
|
|
465
610
|
|
|
466
611
|
|
|
@@ -529,42 +674,35 @@ got('http://unix:/var/run/docker.sock:/containers/json');
|
|
|
529
674
|
got('unix:/var/run/docker.sock:/containers/json');
|
|
530
675
|
```
|
|
531
676
|
|
|
677
|
+
|
|
532
678
|
## AWS
|
|
533
679
|
|
|
534
|
-
Requests to AWS services need to have their headers signed. This can be accomplished by using the [`aws4`](https://www.npmjs.com/package/aws4) package. This is an example for querying an ["
|
|
680
|
+
Requests to AWS services need to have their headers signed. This can be accomplished by using the [`aws4`](https://www.npmjs.com/package/aws4) package. This is an example for querying an ["API Gateway"](https://docs.aws.amazon.com/apigateway/api-reference/signing-requests/) with a signed request.
|
|
535
681
|
|
|
536
682
|
```js
|
|
537
|
-
const url = require('url');
|
|
538
683
|
const AWS = require('aws-sdk');
|
|
539
684
|
const aws4 = require('aws4');
|
|
540
685
|
const got = require('got');
|
|
541
|
-
const config = require('./config');
|
|
542
686
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
aws4.sign(opts, awsConfig.credentials);
|
|
560
|
-
|
|
561
|
-
return got(opts);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
request(`https://${config.host}/production/users/1`);
|
|
687
|
+
const credentials = await new AWS.CredentialProviderChain().resolvePromise();
|
|
688
|
+
|
|
689
|
+
// Create a Got instance to use relative paths and signed requests
|
|
690
|
+
const awsClient = got.extend(
|
|
691
|
+
{
|
|
692
|
+
baseUrl: 'https://<api-id>.execute-api.<api-region>.amazonaws.com/<stage>/',
|
|
693
|
+
hooks: {
|
|
694
|
+
beforeRequest: [
|
|
695
|
+
async options => {
|
|
696
|
+
await credentials.getPromise();
|
|
697
|
+
aws4.sign(options, credentials);
|
|
698
|
+
}
|
|
699
|
+
]
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
);
|
|
565
703
|
|
|
566
|
-
|
|
567
|
-
//
|
|
704
|
+
const response = await awsClient('endpoint/path', {
|
|
705
|
+
// Request-specific options
|
|
568
706
|
});
|
|
569
707
|
```
|
|
570
708
|
|
|
@@ -611,7 +749,7 @@ const createTestServer = require('create-test-server');
|
|
|
611
749
|
|
|
612
750
|
### User Agent
|
|
613
751
|
|
|
614
|
-
It's a good idea to set the `'user-agent'` header so the provider can more easily see how their resource is used. By default, it's the URL to this repo.
|
|
752
|
+
It's a good idea to set the `'user-agent'` header so the provider can more easily see how their resource is used. By default, it's the URL to this repo. You can omit this header by setting it to `null`.
|
|
615
753
|
|
|
616
754
|
```js
|
|
617
755
|
const got = require('got');
|
|
@@ -622,12 +760,42 @@ got('sindresorhus.com', {
|
|
|
622
760
|
'user-agent': `my-module/${pkg.version} (https://github.com/username/my-module)`
|
|
623
761
|
}
|
|
624
762
|
});
|
|
763
|
+
|
|
764
|
+
got('sindresorhus.com', {
|
|
765
|
+
headers: {
|
|
766
|
+
'user-agent': null
|
|
767
|
+
}
|
|
768
|
+
});
|
|
625
769
|
```
|
|
626
770
|
|
|
627
771
|
### 304 Responses
|
|
628
772
|
|
|
629
773
|
Bear in mind, if you send an `if-modified-since` header and receive a `304 Not Modified` response, the body will be empty. It's your responsibility to cache and retrieve the body contents.
|
|
630
774
|
|
|
775
|
+
### Custom endpoints
|
|
776
|
+
|
|
777
|
+
Use `got.extend()` to make it nicer to work with REST APIs. Especially if you use the `baseUrl` option.
|
|
778
|
+
|
|
779
|
+
**Note:** Not to be confused with [`got.create()`](advanced-creation.md), which has no defaults.
|
|
780
|
+
|
|
781
|
+
```js
|
|
782
|
+
const got = require('got');
|
|
783
|
+
const pkg = require('./package.json');
|
|
784
|
+
|
|
785
|
+
const custom = got.extend({
|
|
786
|
+
baseUrl: 'example.com',
|
|
787
|
+
json: true,
|
|
788
|
+
headers: {
|
|
789
|
+
'user-agent': `my-module/${pkg.version} (https://github.com/username/my-module)`
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// Use `custom` exactly how you use `got`
|
|
794
|
+
(async () => {
|
|
795
|
+
const list = await custom('/v1/users/list');
|
|
796
|
+
})();
|
|
797
|
+
```
|
|
798
|
+
|
|
631
799
|
|
|
632
800
|
## Related
|
|
633
801
|
|
|
@@ -638,11 +806,11 @@ Bear in mind, if you send an `if-modified-since` header and receive a `304 Not M
|
|
|
638
806
|
- [GotQL](https://github.com/khaosdoctor/gotql) - Got convenience wrapper to interact with GraphQL using JSON-parsed queries instead of strings
|
|
639
807
|
|
|
640
808
|
|
|
641
|
-
##
|
|
809
|
+
## Maintainers
|
|
642
810
|
|
|
643
|
-
[](https://sindresorhus.com) | [](https://github.com/floatdrop) | [](https://github.com/AlexTes) | [](https://github.com/lukechilds)
|
|
644
|
-
|
|
645
|
-
[Sindre Sorhus](https://sindresorhus.com) | [Vsevolod Strukchinsky](https://github.com/floatdrop) | [Alexander Tesfamichael](https://alextes.me) | [Luke Childs](https://github.com/lukechilds)
|
|
811
|
+
[](https://sindresorhus.com) | [](https://github.com/floatdrop) | [](https://github.com/AlexTes) | [](https://github.com/lukechilds) | [](https://github.com/szmarczak) | [](https://github.com/brandon93s)
|
|
812
|
+
---|---|---|---|---|---
|
|
813
|
+
[Sindre Sorhus](https://sindresorhus.com) | [Vsevolod Strukchinsky](https://github.com/floatdrop) | [Alexander Tesfamichael](https://alextes.me) | [Luke Childs](https://github.com/lukechilds) | [Szymon Marczak](https://github.com/szmarczak) | [Brandon Smith](https://github.com/brandon93s)
|
|
646
814
|
|
|
647
815
|
|
|
648
816
|
## License
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const EventEmitter = require('events');
|
|
3
|
+
const getStream = require('get-stream');
|
|
4
|
+
const is = require('@sindresorhus/is');
|
|
5
|
+
const PCancelable = require('p-cancelable');
|
|
6
|
+
const requestAsEventEmitter = require('./request-as-event-emitter');
|
|
7
|
+
const {HTTPError, ParseError, ReadError} = require('./errors');
|
|
8
|
+
|
|
9
|
+
module.exports = options => {
|
|
10
|
+
const proxy = new EventEmitter();
|
|
11
|
+
|
|
12
|
+
const cancelable = new PCancelable((resolve, reject, onCancel) => {
|
|
13
|
+
const emitter = requestAsEventEmitter(options);
|
|
14
|
+
let cancelOnRequest = false;
|
|
15
|
+
|
|
16
|
+
onCancel(() => {
|
|
17
|
+
cancelOnRequest = true;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
emitter.on('request', request => {
|
|
21
|
+
if (cancelOnRequest) {
|
|
22
|
+
request.abort();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
proxy.emit('request', request);
|
|
26
|
+
|
|
27
|
+
const uploadComplete = () => {
|
|
28
|
+
request.emit('upload-complete');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
onCancel(() => {
|
|
32
|
+
request.abort();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (is.nodeStream(options.body)) {
|
|
36
|
+
options.body.once('end', uploadComplete);
|
|
37
|
+
options.body.pipe(request);
|
|
38
|
+
options.body = undefined;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
request.end(options.body, uploadComplete);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
emitter.on('response', async response => {
|
|
46
|
+
proxy.emit('response', response);
|
|
47
|
+
|
|
48
|
+
const stream = is.null(options.encoding) ? getStream.buffer(response) : getStream(response, options);
|
|
49
|
+
|
|
50
|
+
let data;
|
|
51
|
+
try {
|
|
52
|
+
data = await stream;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
reject(new ReadError(error, options));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const {statusCode} = response;
|
|
59
|
+
const limitStatusCode = options.followRedirect ? 299 : 399;
|
|
60
|
+
|
|
61
|
+
response.body = data;
|
|
62
|
+
|
|
63
|
+
if (options.json && response.body) {
|
|
64
|
+
try {
|
|
65
|
+
response.body = JSON.parse(response.body);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (statusCode >= 200 && statusCode < 300) {
|
|
68
|
+
const parseError = new ParseError(error, statusCode, options, data);
|
|
69
|
+
Object.defineProperty(parseError, 'response', {value: response});
|
|
70
|
+
reject(parseError);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
|
|
76
|
+
const error = new HTTPError(statusCode, response.statusMessage, response.headers, options);
|
|
77
|
+
Object.defineProperty(error, 'response', {value: response});
|
|
78
|
+
emitter.emit('retry', error, retried => {
|
|
79
|
+
if (!retried) {
|
|
80
|
+
if (options.throwHttpErrors) {
|
|
81
|
+
reject(error);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
resolve(response);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
resolve(response);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
emitter.once('error', reject);
|
|
95
|
+
[
|
|
96
|
+
'redirect',
|
|
97
|
+
'uploadProgress',
|
|
98
|
+
'downloadProgress'
|
|
99
|
+
].forEach(event => emitter.on(event, (...args) => proxy.emit(event, ...args)));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const promise = cancelable;
|
|
103
|
+
|
|
104
|
+
promise.cancel = cancelable.cancel.bind(cancelable);
|
|
105
|
+
|
|
106
|
+
promise.on = (name, fn) => {
|
|
107
|
+
proxy.on(name, fn);
|
|
108
|
+
return promise;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return promise;
|
|
112
|
+
};
|