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