Introduction to fetch

Original author: Matt Gaunt
  • Transfer

Goodbye XMLHttpRequest!


fetch()allows you to make queries similar to XMLHttpRequest (XHR). The main difference is that the Fetch API uses Promises , which allow you to use a simpler and cleaner API, avoid the disastrous number of callbacks and the need to remember the API for XMLHttpRequest.


The Fetch API has become available to users along with Service Workers in the global scope in Chrome 40, but already in version 42 it will be available in the window scope. Of course, for all other browsers that do not yet support fetch, there is a polyfile from GitHub , which is available today.

Simple Fetch Request


Let's start by comparing a simple example implemented with XMLHttpRequestand fetch. All we will do in this example is make a request to the URL, get the response and parse it as JSON.

XMLHttpRequest


The XMLHttpRequest example will require us to install two event handlers on successand error, and also call two methods: open()and send(). An example from the MDN documentation :

function reqListener() {  
  var data = JSON.parse(this.responseText);  
  console.log(data);  
}
function reqError(err) {  
  console.log('Fetch Error :-S', err);  
}
var oReq = new XMLHttpRequest();  
oReq.onload = reqListener;  
oReq.onerror = reqError;  
oReq.open('get', './api/some.json', true);  
oReq.send();

Fetch


Our fetch request will look like this:
fetch('./api/some.json')  
  .then(  
    function(response) {  
      if (response.status !== 200) {  
        console.log('Looks like there was a problem. Status Code: ' +  
          response.status);  
        return;  
      }
      // Examine the text in the response  
      response.json().then(function(data) {  
        console.log(data);  
      });  
    }  
  )  
  .catch(function(err) {  
    console.log('Fetch Error :-S', err);  
  });


First of all, we check the status of the response and check whether the request was successfully completed (we expect 200 status). If all is well, then parse the response as JSON.

The answer fetch()is a Stream object . This means that as a result of the method call json()we get Promise, because reading from such an object is asynchronous.

Response Metadata


In the previous example, we examined how you can check the status of a response object and condition the response itself in JSON. The rest of the metadata that you can access (for example, headers) is shown below:

fetch('users.json').then(function(response) {  
    console.log(response.headers.get('Content-Type'));  
    console.log(response.headers.get('Date'));
    console.log(response.status);  
    console.log(response.statusText);  
    console.log(response.type);  
    console.log(response.url);  
});

Response types


When we make a fetch request, the response will be given the type “basic”, “cors” or “opaque”. These “types” indicate which resource the data came from and can be used to determine the data processing process.

When a request is made to a resource located on the same origin ( meaning that the request is executed within the same site. Approx. Per. ), The response will contain the type “basic” and there will be no restrictions for such a request.

If the request is made from one origin to another (cross-domain request), which, in turn, returned CORSheaders, then the type will be cors. Objects with types “cors” and “basic” are almost identical, however, “cors” somewhat limits the metadata that can be accessed to “Cache-Control”, “Content-Language”, “Content-Type”, “Expires”, "Last-Modified", and "Pragma".

As for “opaque”, it comes in cases when a CORS request is executed, but the remote resource does not return CORS headers. This type of request does not provide access to the data or status header, so we are not able to judge the result of the request. As part of the current implementation, fetch()it is not possible to execute CORS requests from the window scope, and here it is written why. This functionality should be added as soon as the Cache APIwill be accessible from the window object.

You can determine the expected query mode, thereby filtering the results of queries with the wrong type. The request mode can be set to the following:

- “same-origin” is successfully executed only for requests for the same origin, all other requests will be rejected.
- “cors” works the same way as “same-origin” + adds the ability to create requests to third-party sites if they return the corresponding CORS headers.
- “cors-with-forced-preflight” works the same as “cors”, but always sends a test request for verification before the request .
- “no-cors” is used when it is necessary to execute a request to origin, which does not send CORS headers and the result of execution is an object of type “opaque”. As mentioned above, at the moment this is not possible in the window window.

To determine the request mode, add the options object as the second parameter to the request and set “mode” in this object:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})  
  .then(function(response) {  
    return response.text();  
  })  
  .then(function(text) {  
    console.log('Request successful', text);  
  })  
  .catch(function(error) {  
    log('Request failed', error)  
  });

Promises Chains


One of the great features of Promises is the ability to group them in chains. If we talk about them in scopes fetch(), then they allow us to “fumble” the logic between requests.

If you work with the JSON API, you will need to check the status and parse the JSON for each response. You can simplify your code by defining status parsing and JSON as separate functions that Promises will return. You will only have to think about processing the data itself and, of course, exceptions.

function status(response) {  
  if (response.status >= 200 && response.status < 300) {  
    return Promise.resolve(response)  
  } else {  
    return Promise.reject(new Error(response.statusText))  
  }  
}
function json(response) {  
  return response.json()  
}
fetch('users.json')  
  .then(status)  
  .then(json)  
  .then(function(data) {  
    console.log('Request succeeded with JSON response', data);  
  }).catch(function(error) {  
    console.log('Request failed', error);  
  });

We define a function that checks response.statusand returns the result: Promise.resolve()or Promise.reject(). This is the first method called in our chain, and if it succeeds ( Promise.resolve()), then the next method is called - fetch()which, in turn, again returns Promise from response.json(). After this call, if successful, we will have a ready-made JSON object. If the parsing fails, Promise will be canceled and the exception condition will be triggered.

But the best thing here is the ability to reuse such code for all fetch requests in the application. Such code is easier to maintain, read, and test.

POST request


For a long time you will not be surprised at the need to use the POST method with passing parameters in the "body" of the request to work with the API.
To implement such a request, we must specify the appropriate parameters in the settings object fetch():

fetch(url, {  
    method: 'post',  
    headers: {  
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"  
    },  
    body: 'foo=bar&lorem=ipsum'  
  })
  .then(json)  
  .then(function (data) {  
    console.log('Request succeeded with JSON response', data);  
  })  
  .catch(function (error) {  
    console.log('Request failed', error);  
  });

Sending credentials via Fetch request


If you want to send a request with some credentials (for example, with a cookie), you should set the credentials in the request options to include:

fetch(url, {  
  credentials: 'include'  
})

FAQ


Can I cancel the fetch()request?
This is not possible at the moment, but it is being actively discussed on GitHub.

Is there a polyfill?
Yes.

Why is no-cors implemented for service workers, but not for window?
This was done for security reasons. More details can be found here .

Also popular now: