node-fetch

npm version build status coverage status

A light-weight module that brings window.fetch to Node.js

Motivation

Instead of implementing XMLHttpRequest in Node.js to run browser-specific Fetch polyfill, 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.

See Matt Andrews’ isomorphic-fetch for isomorphic usage (exports node-fetch for server-side, whatwg-fetch for client-side).

Features

  • Stay consistent with window.fetch API.
  • Make conscious trade-off when following whatwg fetch spec and stream spec implementation details, document known difference.
  • Use native promise, but allow substituting it with [insert your favorite promise library].
  • Use native stream for body, on both request and response.
  • Decode content encoding (gzip/deflate) properly, and convert string output (such as res.text() and res.json()) to UTF-8 automatically.
  • Useful extensions such as timeout, redirect limit, response size limit, explicit errors for troubleshooting.

Difference from client-side fetch

  • See Known Differences for details.
  • If you happen to use a missing feature that window.fetch offers, feel free to open an issue.
  • Pull requests are welcomed too!

Install

npm install node-fetch --save

Usage

  1. var fetch = require('node-fetch');
  2. // if you are on node v0.10, set a Promise library first, eg.
  3. // fetch.Promise = require('bluebird');
  4. // plain text or html
  5. fetch('https://github.com/')
  6. .then(function(res) {
  7. return res.text();
  8. }).then(function(body) {
  9. console.log(body);
  10. });
  11. // json
  12. fetch('https://api.github.com/users/github')
  13. .then(function(res) {
  14. return res.json();
  15. }).then(function(json) {
  16. console.log(json);
  17. });
  18. // catching network error
  19. // 3xx-5xx responses are NOT network errors, and should be handled in then()
  20. // you only need one catch() at the end of your promise chain
  21. fetch('http://domain.invalid/')
  22. .catch(function(err) {
  23. console.log(err);
  24. });
  25. // stream
  26. // the node.js way is to use stream when possible
  27. fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
  28. .then(function(res) {
  29. var dest = fs.createWriteStream('./octocat.png');
  30. res.body.pipe(dest);
  31. });
  32. // buffer
  33. // if you prefer to cache binary data in full, use buffer()
  34. // note that buffer() is a node-fetch only API
  35. var fileType = require('file-type');
  36. fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
  37. .then(function(res) {
  38. return res.buffer();
  39. }).then(function(buffer) {
  40. fileType(buffer);
  41. });
  42. // meta
  43. fetch('https://github.com/')
  44. .then(function(res) {
  45. console.log(res.ok);
  46. console.log(res.status);
  47. console.log(res.statusText);
  48. console.log(res.headers.raw());
  49. console.log(res.headers.get('content-type'));
  50. });
  51. // post
  52. fetch('http://httpbin.org/post', { method: 'POST', body: 'a=1' })
  53. .then(function(res) {
  54. return res.json();
  55. }).then(function(json) {
  56. console.log(json);
  57. });
  58. // post with stream from resumer
  59. var resumer = require('resumer');
  60. var stream = resumer().queue('a=1').end();
  61. fetch('http://httpbin.org/post', { method: 'POST', body: stream })
  62. .then(function(res) {
  63. return res.json();
  64. }).then(function(json) {
  65. console.log(json);
  66. });
  67. // post with form-data (detect multipart)
  68. var FormData = require('form-data');
  69. var form = new FormData();
  70. form.append('a', 1);
  71. fetch('http://httpbin.org/post', { method: 'POST', body: form })
  72. .then(function(res) {
  73. return res.json();
  74. }).then(function(json) {
  75. console.log(json);
  76. });
  77. // post with form-data (custom headers)
  78. // note that getHeaders() is non-standard API
  79. var FormData = require('form-data');
  80. var form = new FormData();
  81. form.append('a', 1);
  82. fetch('http://httpbin.org/post', { method: 'POST', body: form, headers: form.getHeaders() })
  83. .then(function(res) {
  84. return res.json();
  85. }).then(function(json) {
  86. console.log(json);
  87. });
  88. // node 0.12+, yield with co
  89. var co = require('co');
  90. co(function *() {
  91. var res = yield fetch('https://api.github.com/users/github');
  92. var json = yield res.json();
  93. console.log(res);
  94. });

See test cases for more examples.

API

fetch(url, options)

Returns a Promise

Url

Should be an absolute url, eg http://example.com/

Options

default values are shown, note that only method, headers, redirect and body are allowed in window.fetch, others are node.js extensions.

  1. {
  2. method: 'GET'
  3. , headers: {} // request header. format {a:'1'} or {b:['1','2','3']}
  4. , redirect: 'follow' // set to `manual` to extract redirect headers, `error` to reject redirect
  5. , follow: 20 // maximum redirect count. 0 to not follow redirect
  6. , timeout: 0 // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies)
  7. , compress: true // support gzip/deflate content encoding. false to disable
  8. , size: 0 // maximum response body size in bytes. 0 to disable
  9. , body: empty // request body. can be a string, buffer, readable stream
  10. , agent: null // http.Agent instance, allows custom proxy, certificate etc.
  11. }

License

MIT

Acknowledgement

Thanks to github/fetch for providing a solid implementation reference.