How to make API calls in Ionic Capacitor Apps
And how to avoid CORS issues
In this post, we will learn how to make REST API calls from an Ionic Capacitor app. This might sound very trivial feature but it actually becomes confusing because of a lot of options available and even becomes an issue because of origin restrictions and CORS issues.
We will explore various options to do these API calls in Ionic (Capacitor) apps, and test the same in Web, Android and iOS apps. Although I’m using a Capacitor app for demo, the solutions are applicable on Cordova as well.
Frameworks
All the options we explore in this post are equally applicable to any of the front-end framework, be it Vanilla JS, Angular, React or Vue. For demo purpose we will use Angular front-end here.
Also, for build environment we will stick to Capacitor. But we’ll see that Capacitor can use Cordova plugins as well.
REST API call issues
Before we explore the options to do http API calls, we need to understand why different options exist and how they are different.
When we make REST API calls to a server, we often encounter CORS (Cross-Origin Resource Sharing) issues. This happens because our REST API calls contain the information of the request’s origin. E.g. If we are making the call from ionic serve
, the origin will be http://localhost:8100
or similar. The server receiving the request decides whether it will allow an API call from this origin or not. More info in Ionic’s documentation.
Similarly when you make API calls from Ionic Capacitor Android or iOS app, the origin is capacitor://localhost
and http://localhost
respectively. For Cordova it is ionic://localhost
in iOS, and http://localhost
for android. These origins, again, will not be allowed in standard server like Firebase cloud, wooCommerce or Payment gateways etc.
Case 1 — If you have your own server, OR the server has no origin restriction
Life’s good then. If you have your own server where your API calls are ‘hitting’, you can make changes to allow these origins in the requests and problem solved. This can almost exclusively happen only if you are deploying the front-end and back-end yourself.
If the server is not in your control, AND the server has no origin restriction, your API calls will still go through without any issue.
In this case, we can use Angular Http Client for making REST API Calls. We’ll explore more on this in next section.
Since not every server is relaxed in origin restrictions, we need some other solution to avoid CORS issues.
Case 2— You don’t have control over the server
This is the case most of the times. You need to make sure your requests are going through some kind of proxy (outside the webview), even if the request is actually made from the native app or localhost.
This old blog sheds some light on possible options to avoid CORS issues in Ionic. But there are some new methods we can implement for this issues
Choices in Ionic Capacitor apps for Http API calls
For making REST API calls, we have following options
- Fetch — Default API to make Http calls
- Angular HttpClient (Since we are using Angular for Demo. Similar options might be there in React as well) —This is Angular’s default way of making Http calls. If doesn’t fix CORS issues, but has few advantages over fetch API. You can check the advantages in this comparison.
- @ionic-native/http plugin — Works with cordova-plugin-advanced-http — Works only on device, so development is difficult. Fixes the CORS issues.
- Ionic Native Http Connection Backend — This package combines the above two. Essentially Angular HttpClient will work in browser, and will switch to @ionic-native/http when on device. Fixes CORS issue.
Option #3 looks good for our case, but involves Cordova plugins. This is OK if your app uses Cordova, but for Capacitor you might wanna avoid Cordova plugins. This leaves us with the final option
5. Capacitor/Http plugin — Works in browser, Android and iOS. Fixes CORS issue. This plugin essentially does the same as Option#3, but with less number of dependencies.
Let’s explore all these options with code samples and see their limitations.
Demo Server
We will make a Firebase server (local) using firebase serve
and use it for the testing purpose. This is a standard method to run Firebase server locally, OR you can use Firebase Emulator, which is an advanced version of firebase serve
. Here’s a short blog on how to run Firebase Emulator locally.
Once the server is up, we will access it from all three platforms — Web, Android and iOS.
How to access locally run server from device
You might be wondering how to access a locally run server (running on localhost:XXXX) from your device when you build the app.
- First you need to make sure your device is on the same WiFi as your server system
- You need to know the IPv4 of your system. For mac, find it with
ifconfig
, for windowsipconfig
. It will be something like192.168.x.x
which is standard for local systems using a WiFi router - Instead of default serve, you need to use
firebase serve -o YOUR_IP
, replaceYOUR_IP
with your actual IPv4 address - When calling APIs, use this IP as the server address, with firebase serve port number, which defaults to 5000
Firebase functions
Firebase functions essentially behave like view
in Django, or API methods in node (Firebase is node!). Following code shows the 4 standard methods and 4 CORS wrapped methods. (If you are new to Firebase functions, check this blog for Firebase Cloud functions with Ionic)
Note that there’s not much being done in the methods, like fetching some data from DB, or writing a new entry. All those functionalities lay ahead of this point, and these bare methods will serve to prove the point of CORS / restriction which we are trying to understand, with different libraries.
The API method URL i.e. http://192.168.0.7:5000/ionic4fullapp/us-central1/getData
in my case, will be output in terminal when you run firebase serve
or emulate
command.
Testing Methodology
We will
- Make API calls to a sample Firebase server which has 4 methods —
getData
(GET),postData
(POST),putData
(PUT),deleteData
(DELETE) which allows all origins and,
4 methods_getData
(GET),_postData
(POST),_putData
(PUT),_deleteData
(DELETE) which put CORS restrictions (by default Firebase feature).
The “unrestricted” APIs are basically wrapped in CORS module, which has the setting to allow all origins. - We’ll explore both these API servers from localhost (web) and device (Android/iOS) — all calling the same server. When using localhost (web), you can
firebase serve
normally as well (without IP info) - We will test these methods for all 5 options we mentioned in Choices section above.
Demo App for Http Calls
We will make a demo Ionic Angular Capacitor app to test the above. Creating the app is very simple. Run
$ ionic start httpTester sidemenu --type=angular --capacitor
The app name is httpTester
, type is sidemenu
and it incorporates Angular and Capacitor.
My environment is —
Ionic: Ionic CLI : 6.16.3 Capacitor: 3.0.2
Utility: cordova-res : 0.15.3 native-run : 1.4.0
System: NodeJS : v14.15.4 npm : 7.17.0 OS : macOS Big Sur
I have made custom UI to display the behavior across all options. Here’s a sample Page for Fetch API
You can see the ❌ and ✅ marks for success and error in API calls. We’ll perform this routine on all
- Restricted and non-restricted API calls
- Platform wise behavior
- Behavior for each library / plugin
- Behavior for each method type i.e. GET, POST, PUT, DELETE
and finally overlap the results to see which library is best for our usage.
Note: The behavior of GET, POST, PUT, DELETE methods for a particular set of variables remain same in all cases. In other words, if one fails, all will fails, if one succeeds, all will.
Running the app
Once you install the required libraries for a particular option (We will see how to install each library in individual sections), you can simply run the app with following options :
Web
For web testing, you can simply run the app with
$ ionic serve
Android / iOS
For Android and iOS, you will have to build the app , open the corresponding native IDE and build the app. Here are the steps
// Create platform $ npx cap add android // replace `android` with `ios` for iOS
// Build app $ ionic build // replace `android` with `ios` for iOS
// Sync data with native app $ npx cap sync // replace `android` with `ios` for iOS
// Open native IDE to build app $ npx cap open android // replace `android` with `ios` for iOS
After every change in the app, you need to run ionic build
and npx cap copy
to reflect changes in Android /iOS build.
Let’s start with the libraries/plugins one by one
1. Fetch API
Let’s start with web default Fetch API. You don’t need to setup anything to use Fetch. It’s the default for JS.
Here’s the sample code for the unrestricted set of methods (the restricted set will be exact same, with only change in API method name). Here’s how the code looks
Ignore the variables and changeStatus
method. These are only for displaying the ❌ and ✅ in the UI for better visualization of results.
For Fetch API, here’s the overall result for Web, Android and iOS
2. Angular HttpClient
Angular HttpClient
comes with Angular setup in form of the @angular/common/http
package. It can be imported in any .ts
file and used as http client. Just add this in the page’s module.ts
file
import { HttpClientModule } from '@angular/common/http';
.... @NgModule({ ... imports: [HttpClientModule], providers:[..] })
Here’s how the code looks for HttpClient
For Angular HttpClient, here’s the overall result for Web, Android and iOS
3. Ionic Native Http Plugin (Cordova)
Install the Ionic Native Http Plugin by running
$ npm install cordova-plugin-advanced-http $ npm install @ionic-native/http
Also, in the page’s module.ts
file , add
import { HTTP } from '@ionic-native/http/ngx'; .... @NgModule({ ... imports: [...], providers:[HTTP] })
Since this is a Cordova plugin, it will not work on Web. But note that we can use this plugin in a Capacitor app, as Capacitor supports Cordova plugins.
Also post install, you’ll have to run npx cap sync
for Android and iOS. Here’s how to code looks for this plugin
For Ionic Native Http, here’s the overall result for Web, Android and iOS
4. Ionic Native Http connection backend
For this options, you’ll need another plugin which combines the power of httpClient
and Ionic Native Http plugin. Install this plugin using
$ npm install --save ionic-native-http-connection-backend
// In some cases, it might ask to install a dependency cordova-plugin-file
$ npm install cordova-plugin-file $ npm install @ionic-native/file
Again note that we can use this plugin in a Capacitor app, as Capacitor supports Cordova plugins.
You’ll need to take few extra measures here:
- Add
NativeHttpModule
,NativeHttpBackend
andNativeHttpFallback
into the module where you are using the plugins. If you plan to use it throughout the app, add these inapp.module.ts
Here’s how the code will look for calling APIs using this module
Notice we haven’t added import { HTTP } from ‘@ionic-native/http/ngx’;
in this page, but that is automatically attached to API calls when run on device.
For Ionic Native Advanced Http, here’s the overall result for Web, Android and iOS
5. Capacitor Http
This plugin will run only in a Capacitor app. Install the plugin using
$ npm install @capacitor-community/http
No additional configuration required for Android and iOS. You can use it in the page as
For Capacitor Http, here’s the overall result for Web, Android and iOS
Conclusion
We saw several options to call APIs in an Ionic Capacitor Angular app. We saw how the plugin can behave differently in Web vs Android/iOS environment, and also if the server is allowing all origins or not.
Here’s a gist of which library to use when
- Fetch — Use it when you are making an app where you can control the server
Allow-origin
behavior. You can sent the server to accept your app’s origins, and then Fetch will work for all scenarios - Angular HttpClient — Same as Fetch
- Ionic Native Http — Can by-pass allow-origin restriction on Android/iOS device. But it cannot run on web, so development is difficult
- Ionic Native Advanced Http — This allows you to run the APIs in web, android and iOS, but still cannot run origin restricted APIs on web
- Capacitor Http — This allows you to run the APIs in web, android and iOS, but still cannot run origin restricted APIs on web
In conclusion, Capacitor Http and Ionic Native Advanced Http plugins will provide the same level of functionality for Ionic apps. Only difference being the nature of build environment —
- While Ionic Native Advanced Http can run both in Cordova and Capacitor apps, Capacitor Http runs only in Capacitor environment
- While Capacitor Http can run on Ionic-Angular, Ionic-React and Ionic Vue frameworks, Ionic Native Advanced Http Ionic Native Advanced Http can be used only in Ionic-Angular
So in essence it’s a tie ! 🤜 🤛 I personally like Capacitor Http, as it is just one plugin to be installed instead of 4 packages in Ionic Native Advanced case.
Hope this post will clarify few of your Http call doubts.