Introduction to fetch
- 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
XMLHttpRequest
and 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
success
and 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.status
and 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 .