React Native ~ Networking - rohit120582sharma/Documentation GitHub Wiki

Introduction

Many mobile apps need to load resources from a remote URL. You may want to make a POST request to a REST API, or you may simply need to fetch a chunk of static content from another server.

React Native is a complex platform in terms of composition of different patterns, libraries and architectural solutions. Network layer is only a one of many interesting topics that powers the platform.

React Native ships with three network APIs available by default: fetch, XMLHttpRequest and WebSocket.

Neither of these APIs is a part of ECMAScript standard which means that JavaScript doesn’t have any standardised ways of transmitting packages over the wire.

Therefore, if we want to perform network requests from JavaScript, we need to extend its runtime by a custom functionality implemented by the underlying host platform (which is React Native in our case).

So it turns out that React Native should supply/expose fetch, XMLHttpRequest and WebSocket APIs to JS runtime.



Network APIs

XMLHttpRequest

XMLHttpRequest (XHR) is an object that is used to interact with remote resources.

In React Native, XMLHttpRequest consists of two parts: front-end and back-end. The front-end part is something that you can interact with in JavaScript. It is capable of sending appropriate request data to the XHR back-end which is responsible for processing network request and using underlying mobile platform.

The back-end part of XMLHttpRequest is called Networking.

It is an abstraction on top of iOS and Android operating systems that provides a unified API layer that front-end can work with. Implementation of this layer is different for each platform. While on iOS Networking module takes advantage of built-in URLSession, Android version works on top of third-party OkHTTP library that supplies a certain abstraction for low-level Java networking API.

Therefore, once developer make a request, it goes through React Native’s Networking module and underlying operating system right to the requested resource.


Fetch

Fetch is a modern concept equivalent to XMLHttpRequest.

In React Native (in order to not to re-implement a new API for both platforms), it uses GitHub’s whatwg-fetch polyfill that relies on XMLHttpRequest implementation, so it implicitly uses React Native’s Networking module under the hood.

The whatwg-fetch module is a polyfill that implements a subset of the standard Fetch specification, enough to make fetch a viable replacement for most uses of XMLHttpRequest in traditional web applications.

Importing will automatically polyfill window.fetch and related APIs:

import 'whatwg-fetch';

Caveats

  • The Promise returned from fetch() won't reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally, and it will only reject on network failure or if anything prevented the request from completing.

  • fetch is a very explicit API, you don’t get anything unless you ask for it. In order to sending POST request to server; the JSON must be converted to a string and the ‘Content-Type’ header must indicate that the payload is JSON, otherwise the server will treat it as a string.

     fetch('/user', {
     	method: 'POST',
     	headers: {
     		'Content-Type': 'application/json'
     	},
     	body: JSON.stringify({
     		firstName: 'Fred',
     		lastName: 'Flintstone'
     	})
     });
    
  • For CORS requests, use credentials: 'include' to allow sending credentials to other domains:

     fetch('https://example.com:1234/users', {
     	credentials: 'include'
     })
    

WebSocket

WebSocket is a communications protocol, providing full-duplex communication channels over a single TCP connection.

You might already use WebSockets for developing your React Native applications. Every time you start an app in development mode, it creates a WebSocket connection between packager and the app itself, so every time you edit your JS files (or other static assets), it sends a patch signal to the app so it can react to the changes.



Making requests

In order to fetch content from an arbitrary URL, just pass the URL to fetch:

fetch('https://mywebsite.com/mydata.json');

Fetch also takes an optional second argument that allows you to customize the HTTP request. You may want to specify additional headers, or make a POST request:

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

Networking is an inherently asynchronous operation. Fetch methods will return a Promise that makes it straightforward to write code that works in an asynchronous manner:

function getMoviesFromApiAsync() {
	return fetch('https://facebook.github.io/react-native/movies.json')
		.then((response) => response.json())
		.then((responseJson) => {
			return responseJson.movies;
		})
		.catch((error) => {
			console.error(error);
		});
}


iOS configuration

In order to submit an iOS app to Apple's App Store, and to keep it as secure as possible, we have to define the NSAppTransportSecurity inside Info.plist file, in which we can define a list of all the domains the app can make HTTP request to.

By default, iOS is just going to block the requests to unspecified domains. If you need to fetch from a cleartext URL (one that begins with http) you will first need to add an App Transport Security exception.

I know that just setting NSAllowsArbitraryLoads key to true enables your app to make requests for any domain, but since it decreases security, it's not a good option (and you'll have to justify it to Apple during the app review process).

<key>NSAppTransportSecurity</key>
<dict>
	<key>NSAllowsArbitraryLoads</key>
	<true/>
	<key>NSExceptionDomains</key>
	<dict>
		<key>demo.bolty.blue</key>
		<dict>
			<key>NSIncludesSubdomains</key>
			<true/>
			<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
			<true/>
			<key>NSTemporaryExceptionMinimumTLSVersion</key>
			<string>TLSv1.1</string>
		</dict>
	</dict>
</dict>


Issues

Debugging network requests

If you ever developed a mobile application using React Native, you might notice that it exposes a great way of debugging JavaScript code — Chrome Developer Tools (CDT).

Due to implementation specifics, CDT is not capable of handling network requests. If we consider web platform, XHR, fetch and WebSocket APIs are backed by the browser itself which gives it an advantage of having spies that makes it possible to trace network requests. However, React Native doesn’t use Chrome to make networking requests (all network requests goes through the Networking module no matter what), so it can’t trace them.

React Native ships with two interceptors XHRInterceptor for XMLHttpRequest & fetch requests and WebSocketInterceptor for WebSockets accordingly. Interceptors can be spied to trace the remote requests where the Reactotron comes into the pircture.

Reactotron is a swiss knife for React(+Native) development that provides lots of helpful functionality like debugging network requests, redux actions, sagas and much much more.


Sending binary data over the wire

⚠️ **GitHub.com Fallback** ⚠️