1 |
|
2 | node-fetch
|
3 | ==========
|
4 |
|
5 | [![npm version][npm-image]][npm-url]
|
6 | [![build status][travis-image]][travis-url]
|
7 | [![coverage status][codecov-image]][codecov-url]
|
8 |
|
9 | A light-weight module that brings `window.fetch` to Node.js
|
10 |
|
11 |
|
12 | # Motivation
|
13 |
|
14 | Instead 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.
|
15 |
|
16 | See 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).
|
17 |
|
18 |
|
19 | # Features
|
20 |
|
21 | - Stay consistent with `window.fetch` API.
|
22 | - Make conscious trade-off when following [whatwg fetch spec](https://fetch.spec.whatwg.org/) and [stream spec](https://streams.spec.whatwg.org/) implementation details, document known difference.
|
23 | - Use native promise, but allow substituting it with [insert your favorite promise library].
|
24 | - Use native stream for body, on both request and response.
|
25 | - Decode content encoding (gzip/deflate) properly, and convert string output (such as `res.text()` and `res.json()`) to UTF-8 automatically.
|
26 | - Useful extensions such as timeout, redirect limit, response size limit, [explicit errors](https://github.com/bitinn/node-fetch/blob/master/ERROR-HANDLING.md) for troubleshooting.
|
27 |
|
28 |
|
29 | # Difference from client-side fetch
|
30 |
|
31 | - See [Known Differences](https://github.com/bitinn/node-fetch/blob/master/LIMITS.md) for details.
|
32 | - If you happen to use a missing feature that `window.fetch` offers, feel free to open an issue.
|
33 | - Pull requests are welcomed too!
|
34 |
|
35 |
|
36 | # Install
|
37 |
|
38 | `npm install node-fetch --save`
|
39 |
|
40 |
|
41 | # Usage
|
42 |
|
43 | ```javascript
|
44 | import fetch from 'node-fetch';
|
45 | // or
|
46 | // const fetch = require('node-fetch');
|
47 |
|
48 | // if you are using your own Promise library, set it through fetch.Promise. Eg.
|
49 |
|
50 | // import Bluebird from 'bluebird';
|
51 | // fetch.Promise = Bluebird;
|
52 |
|
53 | // plain text or html
|
54 |
|
55 | fetch('https://github.com/')
|
56 | .then(res => res.text())
|
57 | .then(body => console.log(body));
|
58 |
|
59 | // json
|
60 |
|
61 | fetch('https://api.github.com/users/github')
|
62 | .then(res => res.json())
|
63 | .then(json => console.log(json));
|
64 |
|
65 | // catching network error
|
66 | // 3xx-5xx responses are NOT network errors, and should be handled in then()
|
67 | // you only need one catch() at the end of your promise chain
|
68 |
|
69 | fetch('http://domain.invalid/')
|
70 | .catch(err => console.error(err));
|
71 |
|
72 | // stream
|
73 | // the node.js way is to use stream when possible
|
74 |
|
75 | fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
|
76 | .then(res => {
|
77 | const dest = fs.createWriteStream('./octocat.png');
|
78 | res.body.pipe(dest);
|
79 | });
|
80 |
|
81 | // buffer
|
82 | // if you prefer to cache binary data in full, use buffer()
|
83 | // note that buffer() is a node-fetch only API
|
84 |
|
85 | import fileType from 'file-type';
|
86 |
|
87 | fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
|
88 | .then(res => res.buffer())
|
89 | .then(buffer => fileType(buffer))
|
90 | .then(type => { /* ... */ });
|
91 |
|
92 | // meta
|
93 |
|
94 | fetch('https://github.com/')
|
95 | .then(res => {
|
96 | console.log(res.ok);
|
97 | console.log(res.status);
|
98 | console.log(res.statusText);
|
99 | console.log(res.headers.raw());
|
100 | console.log(res.headers.get('content-type'));
|
101 | });
|
102 |
|
103 | // post
|
104 |
|
105 | fetch('http://httpbin.org/post', { method: 'POST', body: 'a=1' })
|
106 | .then(res => res.json())
|
107 | .then(json => console.log(json));
|
108 |
|
109 | // post with stream from file
|
110 |
|
111 | import { createReadStream } from 'fs';
|
112 |
|
113 | const stream = createReadStream('input.txt');
|
114 | fetch('http://httpbin.org/post', { method: 'POST', body: stream })
|
115 | .then(res => res.json())
|
116 | .then(json => console.log(json));
|
117 |
|
118 | // post with JSON
|
119 |
|
120 | var body = { a: 1 };
|
121 | fetch('http://httpbin.org/post', {
|
122 | method: 'POST',
|
123 | body: JSON.stringify(body),
|
124 | headers: { 'Content-Type': 'application/json' },
|
125 | })
|
126 | .then(res => res.json())
|
127 | .then(json => console.log(json));
|
128 |
|
129 | // post with form-data (detect multipart)
|
130 |
|
131 | import FormData from 'form-data';
|
132 |
|
133 | const form = new FormData();
|
134 | form.append('a', 1);
|
135 | fetch('http://httpbin.org/post', { method: 'POST', body: form })
|
136 | .then(res => res.json())
|
137 | .then(json => console.log(json));
|
138 |
|
139 | // post with form-data (custom headers)
|
140 | // note that getHeaders() is non-standard API
|
141 |
|
142 | import FormData from 'form-data';
|
143 |
|
144 | const form = new FormData();
|
145 | form.append('a', 1);
|
146 | fetch('http://httpbin.org/post', { method: 'POST', body: form, headers: form.getHeaders() })
|
147 | .then(res => res.json())
|
148 | .then(json => console.log(json));
|
149 |
|
150 | // node 7+ with async function
|
151 |
|
152 | (async function () {
|
153 | const res = await fetch('https://api.github.com/users/github');
|
154 | const json = await res.json();
|
155 | console.log(json);
|
156 | })();
|
157 | ```
|
158 |
|
159 | See [test cases](https://github.com/bitinn/node-fetch/blob/master/test/test.js) for more examples.
|
160 |
|
161 |
|
162 | # API
|
163 |
|
164 | ## fetch(url, options)
|
165 |
|
166 | Returns a `Promise`
|
167 |
|
168 | ### Url
|
169 |
|
170 | Should be an absolute url, eg `http://example.com/`
|
171 |
|
172 | ### Options
|
173 |
|
174 | Note that only `method`, `headers`, `redirect` and `body` are allowed in `window.fetch`. Other options are node.js extensions. The default values are shown after each option key.
|
175 |
|
176 | ```
|
177 | {
|
178 | method: 'GET'
|
179 | , headers: {} // request header. format {a:'1'} or {b:['1','2','3']}
|
180 | , redirect: 'follow' // set to `manual` to extract redirect headers, `error` to reject redirect
|
181 | , follow: 20 // maximum redirect count. 0 to not follow redirect
|
182 | , timeout: 0 // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies)
|
183 | , compress: true // support gzip/deflate content encoding. false to disable
|
184 | , size: 0 // maximum response body size in bytes. 0 to disable
|
185 | , body: empty // request body. can be a string, buffer, readable stream
|
186 | , agent: null // http.Agent instance, allows custom proxy, certificate etc.
|
187 | }
|
188 | ```
|
189 |
|
190 |
|
191 | # License
|
192 |
|
193 | MIT
|
194 |
|
195 |
|
196 | # Acknowledgement
|
197 |
|
198 | Thanks to [github/fetch](https://github.com/github/fetch) for providing a solid implementation reference.
|
199 |
|
200 |
|
201 | [npm-image]: https://img.shields.io/npm/v/node-fetch.svg?style=flat-square
|
202 | [npm-url]: https://www.npmjs.com/package/node-fetch
|
203 | [travis-image]: https://img.shields.io/travis/bitinn/node-fetch.svg?style=flat-square
|
204 | [travis-url]: https://travis-ci.org/bitinn/node-fetch
|
205 | [codecov-image]: https://img.shields.io/codecov/c/github/bitinn/node-fetch.svg?style=flat-square
|
206 | [codecov-url]: https://codecov.io/gh/bitinn/node-fetch
|