📜 ⬆️ ⬇️

Introduction to fetch

Goodbye XMLHttpRequest!


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


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

Simple Fetch Request


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

XMLHttpRequest


The example with XMLHttpRequest will require us to set two event handlers for success and error , as well as to call two methods: open() and send() . Example from 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 successful (we expect 200 status). If everything is fine, then the parsim response is like JSON.

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

Response metadata


In the previous example, we learned how to check the status of the response object and to convention the response itself in JSON. The remaining metadata you can access (for example, headers) is listed 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); }); 

Types of response


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

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

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

As for the "opaque" - then 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 of fetch() it is not possible to execute CORS requests from the window's skoup, and here it is written why. This functionality should be added as soon as the Cache API is available from the window object.

You can define the expected query mode, thereby filtering the results of queries with the wrong type. Query 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 in 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 a request.
- “no-cors” is used when you need to make a request to origin, which does not send CORS headers and the result of execution is an object with the type “opaque”. As mentioned above, at the moment this is not possible in a window.

To determine the request mode, add an option object with 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 into chains. If we talk about them in fetch() , then they allow us to “fumble” the logic between requests.

If you are working 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 will be returned by promises. You will only 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.status and returns the result: Promise.resolve() or Promise.reject() . This is the first method called in our chain, and if it completes successfully ( Promise.resolve() ), the method following it is called fetch() , which, in turn, returns Promise from response.json() again. After this call, in case of successful execution, we will have a ready-made JSON object. If the parsing fails, Promise will be canceled and the condition for the exception will work.

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 no one will be surprised by the need to use the POST method with passing parameters in the "body" of a request to work with the API.
To make such a request, we need to specify the appropriate parameters in the fetch() settings object:

 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); }); 

We send accounting data through Fetch-request


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

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

FAQ


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

Is there a polyfil?
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 .

Source: https://habr.com/ru/post/252941/


All Articles