Interacting with APIs Using React Native Fetch

Fetch is a fantastic networking API that was chosen for React Native, but because it is relatively new, there are a few things to be aware of when using it. The React Native Documentation does include a single example, which is a good start, but I want to add a few more things that may not be readily obvious.

GET requests

Sending a GET request to a JSON API is the simplest use case. Just call fetch and supply it with the appropriate URL. It returns a promise that can be parsed as usual:

fetch('/users.json')  
.then(function(response) {
return response.json()
})

POST requests

When submitting a POST request, supply the URL as the first argument and an object containing the request information as the second argument.

There are two things to note:

  1. Make sure you send the correct headers. Otherwise, the payload won’t get through.
  2. Stringify the JSON payload before sending it.

As an example, follow the documetation on the React Native website:

fetch('https://mywebsite.com/endpoint/', {  
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})

Or add in some ES6!

Because React Native ships with the Babel Javascript Compiler as of version 0.5.0, we are free to use ES6 enhanced object literals and template strings!

let email = "joe@example.com";  
let password = "donkeybrains";
let myApiUrl = "http://www.example.com/api"
let usersPath = "users"
fetch(`${myApiUrl}/${usersPath}`, {  
.
.
body: JSON.stringify({
user: {email, password}
})
})

Handling API error codes

The React Native documentation warns us that “Errors thrown by rejected Promises need to be caught, or they will be swallowed silently”, which is true — but it is not the only concern.

The thing is, fetch only returns an error when when there is a network error or when something else gets in the way of the network request completing. It does not throw an error if your authentication fails, for instance.

That means that we need to handle HTTP status codes ourself. A good way to do this is to add an API handler utility as recommended in the GitHub page mentioned above.

I like to create a new ApiUtils module to collect my API utility methods:

// ApiUtils.js
var ApiUtils = {  
checkStatus: function(response) {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
let error = new Error(response.statusText);
error.response = response;
throw error;
}
}
};
export { ApiUtils as default };

Our utility takes the Promise response from fetch and checks to see whether the status code is in the 200s. If so, the response is returned back as a promise. If not, an error is thrown, which we will then catch.

Here is a new API object that now employs our ApiUtils.checkStatus method:

// Api.js
import ApiUtils from './ApiUtils'
var Api = {  
getItems: function() {
return fetch(someUrl)
.then(ApiUtils.checkStatus)
.then(response => response.json())
.catch(e => e)
},
.
.

And that’s about it :)

A note about my former blog

This post originally appeared on my blog that once lived at yoniweisbrod.com and has since been hacked. Protect your sites, people, and backup your databases!