Making Fetch Happen: Replacing Native Plugins with Web APIs
Tags: webdev, javascript, pwa, cordova
Published: 2019-12-20 16:07:06

---
title: Making Fetch Happen: Replacing Native Plugins with Web APIs
published: true
date: 2019-11-26 18:42:17 UTC
tags: webdev, javascript, pwa, Cordova,
canonical_url: https://ionicframework.com/blog/replacing-native-plugins-with-web-apis/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/t79qnu47nys237444w4d.png
---

Whenever I need to add a native device feature to an Ionic app, my first instinct is to reach for a native plugin first. However, a built-in browser [Web API](https://developer.mozilla.org/en-US/docs/Web/API) could be the better alternative, offering the same feature set as well as improved performance and reduced maintenance cost.

## Web API Benefits

There are several benefits to using a Web API over a native plugin, including:

* <strong>Reduce app bloat:</strong> By design, native plugins bring in additional code to a project, increasing app download size for your users. A Web API, however, is already available.
* <strong>Increase app performance:</strong> Less plugin code leads to better overall performance. This is especially a factor in app startup timing, where most plugins are initialized and loaded into memory.
* <strong>Reduce app maintenance:</strong> Web APIs are less likely to degrade over time as new mobile operating system updates are released. Browser vendors regularly ship critical security updates as well - no action required by you or your app users.
* <strong>Faster development cycles:</strong> Less reliance on native plugins decreases the need to test on device hardware, which slows down development. That’s what makes `ionic serve` so powerful - build your entire app locally in the browser, then test on a device towards the end of the development cycle.
* <strong>Better cross-platform support:</strong> Web APIs make it easier to bring your app to more platforms. For example, the ability to deploy an iOS or Android app as a PWA.

<!--more-->

## A Real World Example: Switching from File Plugin to Fetch API

There’s an easier way to read a file on a device, which potentially replaces the need for the [Cordova File plugin](https://ionicframework.com/docs/native/file) entirely, by using the [Fetch Web API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). 

<a href="https://blog.ionicframework.com/wp-content/uploads/2019/11/mean-girls-fetch-happen.png"><img src="https://blog.ionicframework.com/wp-content/uploads/2019/11/mean-girls-fetch-happen.png" alt="" class="aligncenter size-full wp-image-3027" /></a>

This is particularly useful when paired with the Cordova Camera plugin:

```typescript
// Capture photo using the device camera
const tempPhoto = await this.camera.getPicture(options);

// Convert from file:// protocol to WebView safe one (avoid CORS)
const webSafePhoto = this.webview.convertFileSrc(tempPhoto);

// Retrieve the photo image data
const response = await fetch(webSafePhoto);
```

I discovered this while building an encrypted image [demo app](https://github.com/ionic-team/demo-encrypted-image-storage). The demo’s main goal was to save an image captured from the device camera into [Ionic Offline Storage](https://ionicframework.com/docs/enterprise/offline-storage). The challenge was that Offline Storage required the image data to be stored as an array buffer, a data format that the Camera plugin didn’t provide.

One solution was to use the Cordova File plugin. This felt clunky and confusing to understand. To make it work, I had to use the File plugin to read the photo file into a `FileEntry` object, then convert it into a `Blob`, then into an `ArrayBuffer`:

```typescript
import { File } from '@ionic-native/file/ngx';

public async saveCameraPhoto() {
  const options: CameraOptions = {
      quality: 100,
      destinationType: this.camera.DestinationType.FILE_URI,
      encodingType: this.camera.EncodingType.JPEG,
      mediaType: this.camera.MediaType.PICTURE
  }
    
  const tempPhoto = await this.camera.getPicture(options);
  
  let fileEntry = await this.file.resolveLocalFilesystemUrl(tempPhoto) as any;
  fileEntry.file((file) => {
    const fileReader = new FileReader();
    
    fileReader.onloadend = () => {
      let blob = new Blob("image/jpeg", fileReader.result as ArrayBuffer);
      const imageDoc = new MutableDocument(“doc”);
      imageDoc.setBlob(“blob”, blob);

      await this.database.save(imageDoc);
     }
  
    fileReader.readAsArrayBuffer(file);
  });
}
```

In contrast, using the Fetch API only required a couple of lines of code.

```typescript
const response = await fetch(webSafePhoto);
const photoArrayBuffer = await response.arraybuffer();
```

The complete example:

```typescript
public async takePicture() {
  const options: CameraOptions = {
      quality: 100,
      destinationType: this.camera.DestinationType.FILE_URI,
      encodingType: this.camera.EncodingType.JPEG,
      mediaType: this.camera.MediaType.PICTURE
  }
    
  const tempPhoto = await this.camera.getPicture(options);
  const webSafePhoto = this.webview.convertFileSrc(tempPhoto);
  const response = await fetch(webSafePhoto);

  // Different data response options:
  const photoBlob = await response.blob();
  const photoArrayBuffer = await response.arraybuffer();
}
```

Cleaner, simpler code that accomplished exactly what I needed. 🤓

## Is a Web API the Right Choice for My App?

While there are many benefits to using a Web API over a native plugin, take some time to evaluate the situation based on your app’s needs. Considerations include:

* <strong>Functionality:</strong> Chances are high that the Web API’s features will differ from the plugin’s. If requirements change in the future, will the Web API be able to cover them? In my Fetch API example, it only retrieves data, so it’s not a complete replacement for the File plugin. If I needed to write a File, I’d go back to using the plugin.
* <strong>Performance:</strong> Web APIs are generally very performant given they are built into the browser. It still makes sense to test as needed, though.
* <strong>Platform Support:</strong> Is the Web API available to my users today, as well as any additional platforms I may support in the future?

Fortunately, checking platform support is easy thanks to two sites:

* [WhatWebCanDo.Today](https://whatwebcando.today/) describes the features of all APIs available.
* [CanIUse.com](https://caniuse.com) covers browser support for each API.

I recommend beginning your search on `WhatWebCanDo.Today` to determine exactly which APIs you might leverage, then do more research on `CanIUse.com` to ensure the API will be available and fully supported on all of the platforms you’re interested in.

Using Fetch as an example, we can see that [it has wide support](https://caniuse.com/#feat=fetch) across all browsers. As Ionic developers targeting iOS and Android, pay close attention to both iOS Safari and Android Browser support:

<a href="https://blog.ionicframework.com/wp-content/uploads/2019/11/real-world-debug-caniusefetch.png"><img src="https://blog.ionicframework.com/wp-content/uploads/2019/11/real-world-debug-caniusefetch.png" alt="caniuse.com - fetch" class="aligncenter size-full wp-image-3024" /></a>

In this case, support began in iOS 10 (10.3) and Android 5 (Chromium 76), so should be safe to use in an Ionic app.

## Web API First

The uniquely powerful benefit of web-based hybrid apps is the ability to leverage both web and native technology as needed.

While every app’s needs are different, explore Web API options first before reaching for a plugin. Though not for everyone, you might be pleasantly surprised at how far they can get you. For more interesting Web API examples, check out my Ionic Native [encrypted storage demo app](https://github.com/ionic-team/demo-encrypted-image-storage).

What are some creative ways you’ve used native web APIs recently? Or plugins you’ve replaced in favor of a web API? Share your insights below.