README.md
1
2node-fetch-npm
3==============
4
5[![npm version][npm-image]][npm-url]
6[![build status][travis-image]][travis-url]
7[![coverage status][codecov-image]][codecov-url]
8
9A light-weight module that brings `window.fetch` to Node.js
10
11`node-fetch-npm` is a fork of [`node-fetch`](https://npm.im/node-fetch) used in
12npm itself, through [`make-fetch-happen`](https://npm.im/make-fetch-happen). It
13has more regular releases and accepts some patches that would not fit with
14`node-fetch`'s own design goals (such as picking a specific cookie library,
15removing `babel` dependency altogether, etc).
16
17This library is *not a replacement* for `node-fetch`, nor does it intend to
18supplant it. It's purely a fork maintained for the sake of easier patching of
19specific needs that it wouldn't be fair to shove down the main project's throat.
20This project will still send patches for shared bugs over and hopefully help
21improve its "parent".
22
23## Motivation
24
25Instead of implementing `XMLHttpRequest` in Node.js to run browser-specific [Fetch polyfill](https://github.com/github/fetch), why not go from native `http` to `fetch` API directly? Hence `node-fetch`, minimal code for a `window.fetch` compatible API on Node.js runtime.
26
27See Matt Andrews' [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) for isomorphic usage (exports `node-fetch` for server-side, `whatwg-fetch` for client-side).
28
29
30## Features
31
32- Stay consistent with `window.fetch` API.
33- Make conscious trade-off when following [whatwg fetch spec][whatwg-fetch] and [stream spec](https://streams.spec.whatwg.org/) implementation details, document known difference.
34- Use native promise, but allow substituting it with [insert your favorite promise library].
35- Use native stream for body, on both request and response.
36- Decode content encoding (gzip/deflate) properly, and convert string output (such as `res.text()` and `res.json()`) to UTF-8 automatically.
37- Useful extensions such as timeout, redirect limit, response size limit, [explicit errors][] for troubleshooting.
38
39
40## Difference from client-side fetch
41
42- See [Known Differences](https://github.com/npm/node-fetch-npm/blob/master/LIMITS.md) for details.
43- If you happen to use a missing feature that `window.fetch` offers, feel free to open an issue.
44- Pull requests are welcomed too!
45
46
47## Install
48
49```sh
50$ npm install node-fetch-npm --save
51```
52
53
54## Usage
55
56```javascript
57import fetch from 'node-fetch';
58// or
59// const fetch = require('node-fetch');
60
61// if you are using your own Promise library, set it through fetch.Promise. Eg.
62
63// import Bluebird from 'bluebird';
64// fetch.Promise = Bluebird;
65
66// plain text or html
67
68fetch('https://github.com/')
69 .then(res => res.text())
70 .then(body => console.log(body));
71
72// json
73
74fetch('https://api.github.com/users/github')
75 .then(res => res.json())
76 .then(json => console.log(json));
77
78// catching network error
79// 3xx-5xx responses are NOT network errors, and should be handled in then()
80// you only need one catch() at the end of your promise chain
81
82fetch('http://domain.invalid/')
83 .catch(err => console.error(err));
84
85// stream
86// the node.js way is to use stream when possible
87
88fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
89 .then(res => {
90 const dest = fs.createWriteStream('./octocat.png');
91 res.body.pipe(dest);
92 });
93
94// buffer
95// if you prefer to cache binary data in full, use buffer()
96// note that buffer() is a node-fetch only API
97
98import fileType from 'file-type';
99
100fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
101 .then(res => res.buffer())
102 .then(buffer => fileType(buffer))
103 .then(type => { /* ... */ });
104
105// meta
106
107fetch('https://github.com/')
108 .then(res => {
109 console.log(res.ok);
110 console.log(res.status);
111 console.log(res.statusText);
112 console.log(res.headers.raw());
113 console.log(res.headers.get('content-type'));
114 });
115
116// post
117
118fetch('http://httpbin.org/post', { method: 'POST', body: 'a=1' })
119 .then(res => res.json())
120 .then(json => console.log(json));
121
122// post with stream from file
123
124import { createReadStream } from 'fs';
125
126const stream = createReadStream('input.txt');
127fetch('http://httpbin.org/post', { method: 'POST', body: stream })
128 .then(res => res.json())
129 .then(json => console.log(json));
130
131// post with JSON
132
133var body = { a: 1 };
134fetch('http://httpbin.org/post', {
135 method: 'POST',
136 body: JSON.stringify(body),
137 headers: { 'Content-Type': 'application/json' },
138})
139 .then(res => res.json())
140 .then(json => console.log(json));
141
142// post with form-data (detect multipart)
143
144import FormData from 'form-data';
145
146const form = new FormData();
147form.append('a', 1);
148fetch('http://httpbin.org/post', { method: 'POST', body: form })
149 .then(res => res.json())
150 .then(json => console.log(json));
151
152// post with form-data (custom headers)
153// note that getHeaders() is non-standard API
154
155import FormData from 'form-data';
156
157const form = new FormData();
158form.append('a', 1);
159fetch('http://httpbin.org/post', { method: 'POST', body: form, headers: form.getHeaders() })
160 .then(res => res.json())
161 .then(json => console.log(json));
162
163// node 7+ with async function
164
165(async function () {
166 const res = await fetch('https://api.github.com/users/github');
167 const json = await res.json();
168 console.log(json);
169})();
170```
171
172See [test cases](https://github.com/npm/node-fetch-npm/blob/master/test/test.js) for more examples.
173
174
175## API
176
177### fetch(url[, options])
178
179- `url` A string representing the URL for fetching
180- `options` [Options](#fetch-options) for the HTTP(S) request
181- Returns: <code>Promise<[Response](#class-response)></code>
182
183Perform an HTTP(S) fetch.
184
185`url` should be an absolute url, such as `http://example.com/`. A path-relative URL (`/file/under/root`) or protocol-relative URL (`//can-be-http-or-https.com/`) will result in a rejected promise.
186
187<a id="fetch-options"></a>
188#### Options
189
190The default values are shown after each option key.
191
192```js
193{
194 // These properties are part of the Fetch Standard
195 method: 'GET',
196 headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below)
197 body: null, // request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream
198 redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect
199
200 // The following properties are node-fetch-npm extensions
201 follow: 20, // maximum redirect count. 0 to not follow redirect
202 timeout: 0, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies)
203 compress: true, // support gzip/deflate content encoding. false to disable
204 size: 0, // maximum response body size in bytes. 0 to disable
205 agent: null // http(s).Agent instance, allows custom proxy, certificate etc.
206}
207```
208
209##### Default Headers
210
211If no values are set, the following request headers will be sent automatically:
212
213Header | Value
214----------------- | --------------------------------------------------------
215`Accept-Encoding` | `gzip,deflate` _(when `options.compress === true`)_
216`Accept` | `*/*`
217`Connection` | `close` _(when no `options.agent` is present)_
218`Content-Length` | _(automatically calculated, if possible)_
219`User-Agent` | `node-fetch-npm/1.0 (+https://github.com/npm/node-fetch-npm)`
220
221<a id="class-request"></a>
222### Class: Request
223
224An HTTP(S) request containing information about URL, method, headers, and the body. This class implements the [Body](#iface-body) interface.
225
226Due to the nature of Node.js, the following properties are not implemented at this moment:
227
228- `type`
229- `destination`
230- `referrer`
231- `referrerPolicy`
232- `mode`
233- `credentials`
234- `cache`
235- `integrity`
236- `keepalive`
237
238The following node-fetch-npm extension properties are provided:
239
240- `follow`
241- `compress`
242- `counter`
243- `agent`
244
245See [options](#fetch-options) for exact meaning of these extensions.
246
247#### new Request(input[, options])
248
249<small>*(spec-compliant)*</small>
250
251- `input` A string representing a URL, or another `Request` (which will be cloned)
252- `options` [Options][#fetch-options] for the HTTP(S) request
253
254Constructs a new `Request` object. The constructor is identical to that in the [browser](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request).
255
256In most cases, directly `fetch(url, options)` is simpler than creating a `Request` object.
257
258<a id="class-response"></a>
259### Class: Response
260
261An HTTP(S) response. This class implements the [Body](#iface-body) interface.
262
263The following properties are not implemented in node-fetch-npm at this moment:
264
265- `Response.error()`
266- `Response.redirect()`
267- `type`
268- `redirected`
269- `trailer`
270
271#### new Response([body[, options]])
272
273<small>*(spec-compliant)*</small>
274
275- `body` A string or [Readable stream][node-readable]
276- `options` A [`ResponseInit`][response-init] options dictionary
277
278Constructs a new `Response` object. The constructor is identical to that in the [browser](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response).
279
280Because Node.js does not implement service workers (for which this class was designed), one rarely has to construct a `Response` directly.
281
282<a id="class-headers"></a>
283### Class: Headers
284
285This class allows manipulating and iterating over a set of HTTP headers. All methods specified in the [Fetch Standard][whatwg-fetch] are implemented.
286
287#### new Headers([init])
288
289<small>*(spec-compliant)*</small>
290
291- `init` Optional argument to pre-fill the `Headers` object
292
293Construct a new `Headers` object. `init` can be either `null`, a `Headers` object, an key-value map object, or any iterable object.
294
295```js
296// Example adapted from https://fetch.spec.whatwg.org/#example-headers-class
297
298const meta = {
299 'Content-Type': 'text/xml',
300 'Breaking-Bad': '<3'
301};
302const headers = new Headers(meta);
303
304// The above is equivalent to
305const meta = [
306 [ 'Content-Type', 'text/xml' ],
307 [ 'Breaking-Bad', '<3' ]
308];
309const headers = new Headers(meta);
310
311// You can in fact use any iterable objects, like a Map or even another Headers
312const meta = new Map();
313meta.set('Content-Type', 'text/xml');
314meta.set('Breaking-Bad', '<3');
315const headers = new Headers(meta);
316const copyOfHeaders = new Headers(headers);
317```
318
319<a id="iface-body"></a>
320### Interface: Body
321
322`Body` is an abstract interface with methods that are applicable to both `Request` and `Response` classes.
323
324The following methods are not yet implemented in node-fetch-npm at this moment:
325
326- `formData()`
327
328#### body.body
329
330<small>*(deviation from spec)*</small>
331
332* Node.js [`Readable` stream][node-readable]
333
334The data encapsulated in the `Body` object. Note that while the [Fetch Standard][whatwg-fetch] requires the property to always be a WHATWG `ReadableStream`, in node-fetch-npm it is a Node.js [`Readable` stream][node-readable].
335
336#### body.bodyUsed
337
338<small>*(spec-compliant)*</small>
339
340* `Boolean`
341
342A boolean property for if this body has been consumed. Per spec, a consumed body cannot be used again.
343
344#### body.arrayBuffer()
345#### body.blob()
346#### body.json()
347#### body.text()
348
349<small>*(spec-compliant)*</small>
350
351* Returns: <code>Promise</code>
352
353Consume the body and return a promise that will resolve to one of these formats.
354
355#### body.buffer()
356
357<small>*(node-fetch-npm extension)*</small>
358
359* Returns: <code>Promise<Buffer></code>
360
361Consume the body and return a promise that will resolve to a Buffer.
362
363#### body.textConverted()
364
365<small>*(node-fetch-npm extension)*</small>
366
367* Returns: <code>Promise<String></code>
368
369Identical to `body.text()`, except instead of always converting to UTF-8, encoding sniffing will be performed and text converted to UTF-8, if possible.
370
371<a id="class-fetcherror"></a>
372### Class: FetchError
373
374<small>*(node-fetch-npm extension)*</small>
375
376An operational error in the fetching process. See [ERROR-HANDLING.md][] for more info.
377
378## License
379
380MIT
381
382
383## Acknowledgement
384
385Thanks to [github/fetch](https://github.com/github/fetch) for providing a solid implementation reference.
386
387
388[npm-image]: https://img.shields.io/npm/v/node-fetch-npm.svg?style=flat-square
389[npm-url]: https://www.npmjs.com/package/node-fetch-npm
390[travis-image]: https://img.shields.io/travis/npm/node-fetch-npm.svg?style=flat-square
391[travis-url]: https://travis-ci.org/npm/node-fetch-npm
392[codecov-image]: https://img.shields.io/codecov/c/github/npm/node-fetch-npm.svg?style=flat-square
393[codecov-url]: https://codecov.io/gh/npm/node-fetch-npm
394[ERROR-HANDLING.md]: https://github.com/npm/node-fetch-npm/blob/master/ERROR-HANDLING.md
395[whatwg-fetch]: https://fetch.spec.whatwg.org/
396[response-init]: https://fetch.spec.whatwg.org/#responseinit
397[node-readable]: https://nodejs.org/api/stream.html#stream_readable_streams
398[mdn-headers]: https://developer.mozilla.org/en-US/docs/Web/API/Headers
399