On this article, we’ll have a look at the right way to use the Fetch API with Node.js, Deno, and Bun.

Desk of Contents

Fetch API vs XMLHttpRequest

Fetching knowledge through an HTTP request is key internet software exercise. You’ll have made such calls within the browser, however the Fetch API is natively supported in Node.js, Deno, and Bun.

In a browser, you would possibly request data from a server so you possibly can show it with out a full display screen refresh. That is usually referred to as an Ajax request or a single web page software (SPA). Between 1999 and 2015, XMLHttpRequest was the one choice — and stays so if you wish to show file upload progress. XMLHttpRequest is a reasonably clunky callback-based API, but it surely permits fine-grained management and, regardless of the title, it’ll deal with responses in codecs apart from XML — corresponding to textual content, binary, JSON, and HTML.

Browsers have applied the Fetch API from 2015. It’s an easier, simpler, extra constant, promise-based different to XMLHttpRequest.

Your server-side code may additionally wish to make HTTP requests — usually to name APIs on different servers. From their first launch, each the Deno and Bun runtimes usefully replicated the browser’s Fetch API in order that related code may run on each the consumer and server. Node.js required a third-party module corresponding to node-fetch or axios till February 2022, when version 18 added the standard Fetch API. It’s nonetheless thought of experimental, however now you can use fetch() in every single place with an identical code normally.

A Primary Fetch Instance

This easy instance fetches response knowledge from a URI:

const response = await fetch('https://instance.com/knowledge.json');

The fetch() name returns a promise which resolves with a Response object offering details about the outcome. You possibly can parse the HTTP response physique right into a JavaScript object utilizing the promise-based .json() technique:

const knowledge = await response.json();



Shopper-side vs Server-side Fetch

The API could also be an identical throughout platforms, however browsers implement restrictions when making client-side fetch() requests:

  • Cross-origin resource sharing (CORS)

    Shopper-side JavaScript can solely talk with API endpoints inside its personal area. A script loaded from https://domainA.com/js/important.js can name any service at https://domainA.com/, corresponding to https://domainA.com/api/ or https://domainA.com/knowledge/.

    It’s unimaginable to name a service on https://domainB.com/ — until that server permits entry by setting an HTTP Access-Control-Allow-Origin header.

  • Content Security Policy (CSP)

    Your websites/apps can set a Content material-Safety-Coverage HTTP header or meta tag to regulate permitted property in a web page. It might probably forestall unintended or malicious injection of scripts, iframes, fonts, pictures, movies, and so forth. For instance, setting default-src 'self' stops fetch() requesting knowledge exterior its personal area (XMLHttpRequest, WebSocket, server-sent occasions, and beacons are additionally restricted).

Server-side Fetch API calls in Node.js, Deno, and Bun have fewer restrictions, and you may request knowledge from any server. That stated, third-party APIs might:

  • require some type of authentication or authorization utilizing keys or OAuth
  • have most request thresholds, corresponding to no multiple name per minute, or
  • make a industrial cost for entry

You should utilize server-side fetch() calls to proxy client-side requests so you possibly can keep away from CORS and CSP points. That stated, keep in mind to be a conscientious internet citizen and don’t bombard companies with 1000’s of requests that might take them down!

Customized Fetch Requests

The instance above requests knowledge from the URI https://instance.com/knowledge.json. Beneath the floor, JavaScript creates a Request object, which represents the total particulars of that request corresponding to the strategy, headers, physique, and extra.

fetch() accepts two arguments:

  • the useful resource – a string or URL object, and
  • an elective choices parameter with additional request settings

For instance:

const response = await fetch('https://instance.com/knowledge.json', {
   technique: 'GET',
   credentials: 'omit',
   redirect: 'error',
   precedence: 'excessive'
});

The choices object can set following properties in Node.js or client-side code:

propertyvalues
techniqueGET (the default), POST, PUT, PATCH, DELETE, or HEAD
headersa string or Headers object
physiqueis usually a string, JSON, blob, and so on.
modesame-origin, no-cors, or cors
credentialsomit, same-origin, or embrace cookies and HTTP authentication headers
redirectcomply with, error, or handbook dealing with of redirects
referrerthe referring URL
integritysubresource integrity hash
signan AbortSignal object to cancel the request

Optionally, you possibly can create a Request object and go it to fetch(). This can be sensible for those who can outline API endpoints prematurely or wish to ship a collection related requests:

const request = new Request('https://instance.com/api/', {
  technique: 'POST',
  physique: '{"a": 1, "b": 2, "c": 3}',
  credentials: 'omit'
});

console.log(`fetching ${ request.url }`);
const response = await fetch(request);

Dealing with HTTP Headers

You possibly can manipulate and look at HTTP headers within the request and response utilizing a Headers object. The API might be acquainted for those who’ve used JavaScript Maps:


const headers = new Headers({
  'Content material-Kind': 'textual content/plain',
});


headers.append('Authorization', 'Primary abc123');


headers.set('Content material-Kind', 'software/json');


const sort = headers.get('Content material-Kind');


if (headers.has('Authorization')) {

   
   headers.delete('Authorization');

}


headers.forEach((worth, title) => {
  console.log(`${ title }: ${ worth }`);
});


const response = await fetch('https://instance.com/knowledge.json', {
   technique: 'GET',
   headers
});


response.headers.forEach((worth, title) => {
  console.log(`${ title }: ${ worth }`);
});

Fetch Promise Resolve and Reject

You would possibly presume a fetch() promise will reject when an endpoint returns a 404 Not Discovered or related server error. It doesn’t! The promise will resolve, as a result of that decision was profitable — even when the outcome wasn’t what you anticipated.

A fetch() promise solely rejects when:

  • you make an invalid request — corresponding to fetch('httttps://!invalidURL/');
  • you abort the fetch() request, or
  • there’s a community error, corresponding to a connection failure

Analyzing Fetch Responses

Profitable fetch() calls return a Response object containing details about the state and returned knowledge. The properties are:

propertydescription
okaytrue if the response was profitable
standingthe HTTP standing code, corresponding to 200 for achievement
statusTextthe HTTP standing textual content, corresponding to OK for a 200 code
urlthe URL
redirectedtrue if the request was redirected
sortthe response sort: fundamental, cors, error, opaque, or opaqueredirect
headersthe response Headers object
physiquea ReadableStream of physique content material (or null)
bodyUsedtrue if the physique has been learn

The next Response object strategies all return a promise, so it is best to use await or .then blocks:

techniquedescription
textual content()returns the physique as a string
json()parses the physique to a JavaScript object
arrayBuffer()returns the physique as an ArrayBuffer
blob()returns the physique as a Blob
formData()returns the physique as a FormData object of key/worth pairs
clone()clones the response, usually so you possibly can parse the physique in several methods

const response = await fetch('https://instance.com/knowledge.json');


if ( response.okay && response.headers.get('Content material-Kind') === 'software/json') {

   
   const obj = await response.json();

}

Aborting Fetch Requests

Node.js received’t day trip a fetch() request; it may run endlessly! Browsers may wait between one and 5 minutes. It is best to abort fetch() below regular circumstances the place you’re anticipating a fairly fast response.

The next instance makes use of an AbortController object, which passes a sign property to the second fetch() parameter. A timeout runs the .abort() technique if fetch doesn’t full inside 5 seconds:


const
  controller = new AbortController(),
  sign = controller.sign,
  timeout = setTimeout(() => controller.abort(), 5000);

strive {

  const response = await fetch('https://instance.com/slowrequest/', { sign });

  clearTimeout(timeout);

  console.log( response.okay );

}
catch (err) {

  
  console.log(err);

}

Node.js, Deno, Bun, and most browsers launched since mid-2022 additionally assist AbortSignal. This gives an easier timeout() technique so that you don’t must handle your individual timers:

strive {

  
  const response = await fetch('https://instance.com/slowrequest/', {
    sign: AbortSignal.timeout( 5000 ),
  });

  console.log( response.okay );

}
catch (err) {

  
  console.log(err);

}

Efficient Fetches

Like all asynchronous, promise-based operation, it is best to solely make fetch() calls in collection when the enter of a name depends upon the output of a earlier one. The next code doesn’t carry out in addition to it may as a result of every API name should watch for the earlier one to resolve or reject. If every response takes one second, it’ll take a complete of three seconds to finish:


const response1 = await fetch('https://example1.com/api/');
const response2 = await fetch('https://example2.com/api/');
const response3 = await fetch('https://example3.com/api/');

The Promise.allSettled() method runs guarantees concurrently and fulfills when all have resolved or rejected. This code completes on the pace of the slowest response. It is going to be 3 times quicker:

const knowledge = await Promise.allSettled(
  [
    'https://example1.com/api/',
    'https://example2.com/api/',
    'https://example3.com/api/'
  ].map(url => fetch( url ))
);

knowledge returns an array of objects the place:

  • every has a standing property string of "fullfilled" or "rejected"
  • if resolved, a worth property returns the fetch() response
  • if rejected, a cause property returns the error

Abstract

Except you’re utilizing a legacy model of Node.js (17 or under), the Fetch API is obtainable in JavaScript on each the server and consumer. It’s versatile, straightforward to make use of, and constant throughout all runtimes. A 3rd-party module ought to solely be essential for those who require extra superior performance corresponding to caching, retries, or file dealing with.