npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-native-fetch-api

v3.0.0

Published

A fetch API polyfill for React Native with text streaming support.

Downloads

272,389

Readme

fetch

npm version ci

A fetch API polyfill for React Native with text streaming support

This is a fork of GitHub's fetch polyfill, the fetch implementation React Native currently provides. This project features an alternative fetch implementation directy built on top of React Native's Networking API instead of XMLHttpRequest for performance gains. At the same time, it aims to fill in some gaps of the WHATWG specification for fetch, namely the support for text streaming.

In practice, this implementation is a drop-in replacement to GitHub's polyfill as it closely follows its implementation. Do not use this implementation if your application does not require to stream text.

Motivation

GitHub's fetch polyfill, originally designed with the intention to be used in web browsers without support for the fetch standard, most notably does not support the consumption of a response body as a stream.

However, as React Native does not yet provide direct access to the underlying byte stream for responses, we either have to fallback to XMLHttpRequest or React Native's networking API for iOS and Android. Currently, only strings can be transfered through the bridge, thus binary data has to be base64-encoded (source) and while React Native's XHR provides progress events to receive incremental data, it concatenates the response string as data comes in. Although very inefficient, the response can be sliced up, each chunk encoded into its UTF-8 representation with TextEncoder and finally enqueued to the stream.

Instead of relying on XMLHttpRequest, which degrades performance, we remove it out of the equation and have fetch interact with React Native's Networking API directly instead. To make Response.body work, ReadableStream's controller was integrated with native progress events. It's important to stress that progress events are only fired when the native response type is set to text (https://github.com/facebook/react-native/blob/v0.63.4/Libraries/Network/RCTNetworking.mm#L544-L547), therefore limiting streaming to text-only transfers. If you wish to consume binary data, either blob or base64 response types have to be used. In this case, the downside is that the final response body is read as a whole and enqueued to the stream's controller as a single chunk. There is no way to read a partial response of a binary transfer.

For more context, read the following:

  • https://github.com/github/fetch/issues/746
  • https://github.com/facebook/react-native/issues/27741
  • https://hpbn.co/xmlhttprequest/#streaming-data-with-xhr

Related:

  • https://github.com/react-native-community/discussions-and-proposals/issues/99

Requirements

React Native v0.62.0+ is the minimum version supported where the Networking API has been made public.

This implementation depends on the following web APIs which are not currently available in React Native:

It should be possible remove the dependency on TextEncoder and TextDecoder, but not on ReadableStream. Either way, beware the bundle size of your application will inevitable increase.

To polyfill the above APIs, use react-native-polyfill-globals.

Install

$ npm install react-native-fetch-api --save

Setup

The APIs provided by GitHub's implementation in React Native have to be replaced by those provided by this implementation. To do so, check and install react-native-polyfill-globals and follow the instructions therein.

Usage

No need to import anything after the setup is done. All APIs will be available globally.

Example:

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(json => console.log(json))

Check fetch's official documentation to learn more about the concepts and extended usage.

Enable text streaming

A non-standard option was added to fetch to enable incremental events in React Native's networking layer.

fetch('https://jsonplaceholder.typicode.com/todos/1', { reactNative: { textStreaming: true } })
  .then(response => response.body)
  .then(stream => ...)

Aborting requests

It's possible to abort an on-going request and React Native already supports AbortController, so there is no need for a polyfill.

const controller = new AbortController();

fetch('https://jsonplaceholder.typicode.com/todos/1', { signal: controller.signal })
  .then(response => response.json())
  .then(json => console.log(json))

Learn more about aborting fetch at https://developers.google.com/web/updates/2017/09/abortable-fetch.

Cookies

There is no concept of Cross-Origin Resource Sharing (CORS) in native apps. React Native only accepts a boolean value for the credentials option. As such, to send cookies you can either use same-origin and include.

The Set-Cookie response header returned from the server is a forbidden header name and therefore can't be programmatically read with response.headers.get(). Instead, the platform's native networking stack automatically manages cookies for you.

If you run into issues with cookie-based authentication, read the following:

  • https://reactnative.dev/docs/network#known-issues-with-fetch-and-cookie-based-authentication
  • https://build.affinity.co/persisting-sessions-with-react-native-4c46af3bfd83
  • https://medium.com/locastic/react-native-cookie-based-authentication-80ee18f4c71b

Alternatively, you may consider using the react-native-cookies.

Request caching directive

The only values supported for the cache option are no-cache and no-store and Both achieve exactly the same result. All other values are ignored. Following GitHub's implementation, a cache-busting mechanism is provided by using the query parameter _ which holds the number of milliseconds elapsed since the Epoch when either no-cache or no-store are specified.

Redirect modes directive

The fetch specification defines these values for the redirect option: follow (the default), error, and manual. React Native does not accept such option but it does transparently follow a redirect response given the Location header for 30x status codes.

Tests

To run the test suite, you must use react-native-test-runner CLI. Run the run-tests.js wrapper script to spin up a local HTTP server to execute the networking tests against.

iOS

$ ./run-tests.js --platform ios --simulator '<simulator>' test/index.js 

Where <simulator> can be a combination of a device type and iOS version, e.g. iPhone 11 (14.1), or a device UUID. Check which simulators are available in your system by running the following command:

$ xcrun xctrace list devices

Android

$ ./run-tests.js --platform android --emulator '<emulator>' test/index.js 

Where <emulator> is the name of the Android Virtual Device (AVD), e.g. Pixel_API_28_AOSP. Check which emulators are available in your system by running the following command:

$ emulator -list-avds