Introduction to fetch() api

By Yap Hong Kheng / @hongkheng

XHR


          var xhr = new XmlHttpRequest();
          xhr.open('GET', './some-api/some.json', true);
          xhr.onload = function() {
            if(xhr.status >== 200 && xhr.status <== 301 ) {
              var data = JSON.parse(xhr.responseText);
              console.log(data);
            }
          };
          xhr.onerror = function(err) {
            console.log('Cannot fetch data', err);
          };
          xhr.send();
        

Why?

Replacement for XmlHttpRequest (xhr)

Aim to be more powerful and flexible than XHR

Lower level than XHR

es6

Promise

Use with Service Worker

what is fetch()?


// Basic example, by default is a 'GET' request
fetch('url')
  .then(function(response) {
	// returns a Response object which is a Promise
  });
      

what is fetch()?

Different ways to initialize fetch


 // more common syntax
fetch('url', {
  method: 'PUT',
  headers: {
  	'Content-Type': 'application/json'
  }
}).then(function(response){
	// do something with response
});

what is fetch()?

browsers

what is fetch()?

https://developer.mozilla.org/en/docs/Web/API/Fetch_API

https://fetch.spec.whatwg.org/

Quick Promise refresh

fetch() uses browser native Promise

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise


var p1 = new Promise(function(resolve, reject){
	// do something 
	var response = { some: 'data'};
	// Fulfilled with a value
	resolve(response);
});

p1.then(function(response) {
	console.log('Fulfilled', response);
}).catch(function(reason){ // rejected
	console.log('Error', reason);
});
					

Basic fetch()

es5


fetch('./some-api/some.json')
  .then(function(response){
  if (response.status >== 200 && response.status < 300) {
    return response.json();
  } else {
    var error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}).catch(function(error){
    console.log(error);
});
          

es6


fetch('./some-api/some.json')
.then(response => {
  if (response.status >== 200 && response.status < 300) {
    return response.json();
  } else {
    var error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}).catch(error => {
    console.log(error);
});
          

examples later on will be in es6

Building blocks of fetch

  • Headers - response/request headers
  • Body - Mixin implemented by Response & Request
    • Request
    • Response

fetch() - Headers

In normal XHR headers it willl look like:


...
var basicAuth = 'Basic ' + btoa(username + ':' + password);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.setRequestHeader('Authorization', basicAuth);
...
          

In fetch(), you can pass headers like this. e.g an POST method


  let authHeader = 'Basic ' + btoa(username + ':' + password);

  fetch(url, {
    method: 'POST',
    credentials: 'include',
    headers: {
        'Authorization': authHeader,
        'Content-Type': 'application/json;charset=UTF-8'
    }
  }).then(response => {
    return response.json();
  }); 
  // highlight the headers objects
          

You can also define in a variable form


  var headers = new Headers();
  headers.append(Content-Type','application/json;charset=UTF-8');

  ...
  // define back in fetch
  fetch(url, {
    method: 'POST',
    headers: headers
    ...
  });
        

Query the type of Headers return by the Response


fetch('url').then(response => {
  // determine the how to parse the response type
  // via the headers
  if(response.headers.get('Content-Type') === 'application/json; charset=UTF-8') {
	 return response.json();
  } else {
    return response.text();
  }
}).then(data => data)
.catch(error => error);
						

More on Headers

https://developer.mozilla.org/en-US/docs/Web/API/Headers

fetch() - Request

Create a new Request object to initialize fetch().

Read-only object


						// Note: the url will try to find your root domain url.
var request = new Request('someimage.png');
var url = request.url; // http://yourdomain/someimage.png
fetch(request).then(response => response);

// OR
var request = new Request('someimage.png', {
	method: 'GET'
});

fetch(request).then(response => response); 				

With Service Worker


// from MDN
self.addEventListener('fetch', function(event) {
  console.log('Handling fetch event for', event.request.url);

  event.respondWith(
    caches.match(event.request).then(function(response) {
      if (response) {
        console.log('Found response in cache:', response);

        return response;
      }
      console.log('No response found in cache. About to fetch from network...');

      return fetch(event.request).then(function(response) {
        console.log('Response from network is:', response);

        return response;
      }).catch(function(error) {
        console.error('Fetching failed:', error);

        throw error;
      });
    })
  );
});
						

More on Request

https://developer.mozilla.org/en-US/docs/Web/API/Request

fetch() - Response

Let's look at the response object and see what it returns

http://jsbin.com/yolivap/edit?html,js,output

More on Response

https://developer.mozilla.org/en-US/docs/Web/API/Response

fetch() - Body

Mixin that is implemented by Response & Request

Can be FormData, JSON, string, blob, ArrayBuffer

Passing Data to server


// Passing a JSON data
fetch('url', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json;charset=UTF-8' 
  },
  body: JSON.stringify({ some: 'data'})
});		
	

fetch('url')
	.then(response =>  response.json())
	.then(data => data); // -- this is a parsed JSON data!

//same for plain text
...
return response.text();

// or status message
... 
return response.statusText();
          

More on Body

https://developer.mozilla.org/en-US/docs/Web/API/Body

Handling Errors

Caveat: HTTP error status would not be rejected. It is still consider a valid response.

Solution: Check for valid response.status or response.ok

Throw error when it is not valid and do a catch().


fetch('./some-api/some.json')
  .then(response => {
  // Check for status codes
  if (response.status >== 200 && response.status < 300) {
    return response.json();
  } else {
    var error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}).catch(error => {
    console.log(error);
});
          

Demo

Use fetch with Spotify API

Conclusion

So should you use fetch today?

It isn't finish... so...

polyfill: github/fetch

Issues

  • Cannot abort a sent request
  • No onprogress event (waiting for Streams API)

https://github.com/whatwg/streams

http://blogs.igalia.com/xrcalvar/2015/07/23/readablestream-almost-ready/

Thank you!

Slides: http://hongkheng.github.io/intro-to-fetch-talk-slides/

References:

https://jakearchibald.com/2015/thats-so-fetch/

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API