How to use Apache Cordova client library for Azure Mobile Apps

This guide teaches you to perform common scenarios using the latest Apache Cordova Plugin for Azure Mobile Apps. If you are new to Azure Mobile Apps, first complete Azure Mobile Apps Quick Start to create a backend, create a table, and download a pre-built Apache Cordova project. In this guide, we focus on the client-side Apache Cordova Plugin.

Supported platforms

This SDK supports Apache Cordova v6.0.0 and later on iOS, Android, and Windows devices. The platform support is as follows:

  • Android API 19-24 (KitKat through Nougat).
  • iOS versions 8.0 and later.
  • Windows Phone 8.1.
  • Universal Windows Platform.

Setup and prerequisites

This guide assumes that you have created a backend with a table. This guide assumes that the table has the same schema as the tables in those tutorials. This guide also assumes that you have added the Apache Cordova Plugin to your code. If you have not done so, you may add the Apache Cordova plugin to your project on the command line:

cordova plugin add cordova-plugin-ms-azure-mobile-apps

For more information on creating your first Apache Cordova app, see their documentation.

Setting up an Ionic v2 app

To properly configure an Ionic v2 project, first create a basic app and add the Cordova plugin:

ionic start projectName --v2
cd projectName
ionic plugin add cordova-plugin-ms-azure-mobile-apps

Add the following lines to app.component.ts to create the client object:

declare var WindowsAzure: any;
var client = new WindowsAzure.MobileServiceClient("https://yoursite.azurewebsites.net");

You can now build and run the project in the browser:

ionic platform add browser
ionic run browser

The Azure Mobile Apps Cordova plugin supports both Ionic v1 and v2 apps. Only the Ionic v2 apps require the additional declaration for the WindowsAzure object.

Create a client connection

Create a client connection by creating a WindowsAzure.MobileServiceClient object. Replace appUrl with the URL to your Mobile App.

var client = WindowsAzure.MobileServiceClient(appUrl);

Work with tables

To access or update data, create a reference to the backend table. Replace tableName with the name of your table

var table = client.getTable(tableName);

Once you have a table reference, you can work further with your table:

How to: Query a table reference

Once you have a table reference, you can use it to query for data on the server. Queries are made in a "LINQ-like" language. To return all data from the table, use the following code:

/**
 * Process the results that are received by a call to table.read()
 *
 * @param {Object} results the results as a pseudo-array
 * @param {int} results.length the length of the results array
 * @param {Object} results[] the individual results
 */
function success(results) {
   var numItemsRead = results.length;

   for (var i = 0 ; i < results.length ; i++) {
       var row = results[i];
       // Each row is an object - the properties are the columns
   }
}

function failure(error) {
    throw new Error('Error loading data: ', error);
}

table
    .read()
    .then(success, failure);

The success function is called with the results. Do not use for (var i in results) in the success function as that will iterate over information that is included in the results when other query functions (such as .includeTotalCount()) are used.

For more information on the Query syntax, see the [Query object documentation].

Filtering data on the server

You can use a where clause on the table reference:

table
    .where({ userId: user.userId, complete: false })
    .read()
    .then(success, failure);

You can also use a function that filters the object. In this case, the this variable is assigned to the current object being filtered. The following code is functionally equivalent to the prior example:

function filterByUserId(currentUserId) {
    return this.userId === currentUserId && this.complete === false;
}

table
    .where(filterByUserId, user.userId)
    .read()
    .then(success, failure);

Paging through data

Utilize the take() and skip() methods. For example, if you wish to split the table into 100-row records:

var totalCount = 0, pages = 0;

// Step 1 - get the total number of records
table.includeTotalCount().take(0).read(function (results) {
    totalCount = results.totalCount;
    pages = Math.floor(totalCount/100) + 1;
    loadPage(0);
}, failure);

function loadPage(pageNum) {
    let skip = pageNum * 100;
    table.skip(skip).take(100).read(function (results) {
        for (var i = 0 ; i < results.length ; i++) {
            var row = results[i];
            // Process each row
        }
    }
}

The .includeTotalCount() method is used to add a totalCount field to the results object. The totalCount field is filled with the total number of records that would be returned if no paging is used.

You can then use the pages variable and some UI buttons to provide a page list; use loadPage() to load the new records for each page. Implement caching to speed access to records that have already been loaded.

How to: Return sorted data

Use the .orderBy() or .orderByDescending() query methods:

table
    .orderBy('name')
    .read()
    .then(success, failure);

For more information on the Query object, see the [Query object documentation].

How to: Insert data

Create a JavaScript object with the appropriate date and call table.insert() asynchronously:

var newItem = {
    name: 'My Name',
    signupDate: new Date()
};

table
    .insert(newItem)
    .done(function (insertedItem) {
        var id = insertedItem.id;
    }, failure);

On successful insertion, the inserted item is returned with the additional fields that are required for sync operations. Update your own cache with this information for later updates.

The Azure Mobile Apps Node.js Server SDK supports dynamic schema for development purposes. Dynamic Schema allows you to add columns to the table by specifying them in an insert or update operation. We recommend that you turn off dynamic schema before moving your application to production.

How to: Modify data

Similar to the .insert() method, you should create an Update object and then call .update(). The update object must contain the ID of the record to be updated - the ID is obtained when reading the record or when calling .insert().

var updateItem = {
    id: '7163bc7a-70b2-4dde-98e9-8818969611bd',
    name: 'My New Name'
};

table
    .update(updateItem)
    .done(function (updatedItem) {
        // You can now update your cached copy
    }, failure);

How to: Delete data

To delete a record, call the .del() method. Pass the ID in an object reference:

table
    .del({ id: '7163bc7a-70b2-4dde-98e9-8818969611bd' })
    .done(function () {
        // Record is now deleted - update your cache
    }, failure);

How to: Authenticate users

Azure App Service supports authenticating and authorizing app users using various external identity providers: Facebook, Google, Microsoft Account, and Twitter. You can set permissions on tables to restrict access for specific operations to only authenticated users. You can also use the identity of authenticated users to implement authorization rules in server scripts. For more information, see the Get started with authentication tutorial.

When using authentication in an Apache Cordova app, the following Cordova plugins must be available:

Two authentication flows are supported: a server flow and a client flow. The server flow provides the simplest authentication experience, as it relies on the provider's web authentication interface. The client flow allows for deeper integration with device-specific capabilities such as single-sign-on as it relies on provider-specific device-specific SDKs.

How to: Authenticate with a provider (Server Flow)

To have Mobile Apps manage the authentication process in your app, you must register your app with your identity provider. Then in your Azure App Service, you need to configure the application ID and secret provided by your provider. For more information, see the tutorial Add authentication to your app.

Once you have registered your identity provider, call the .login() method with the name of your provider. For example, to login with Facebook use the following code:

client.login("facebook").done(function (results) {
     alert("You are now logged in as: " + results.userId);
}, function (err) {
     alert("Error: " + err);
});

The valid values for the provider are 'aad', 'facebook', 'google', 'microsoftaccount', and 'twitter'.

Note

Google Authentication does not currently work via Server Flow. To authenticate with Google, you must use a client-flow method.

In this case, Azure App Service manages the OAuth 2.0 authentication flow. It displays the login page of the selected provider and generates an App Service authentication token after successful login with the identity provider. The login function, when complete, returns a JSON object that exposes both the user ID and App Service authentication token in the userId and authenticationToken fields, respectively. This token can be cached and reused until it expires.

How to: Authenticate with a provider (Client Flow)

Your app can also independently contact the identity provider and then provide the returned token to your App Service for authentication. This client flow enables you to provide a single sign-in experience for users or to retrieve additional user data from the identity provider.

Social Authentication basic example

This example uses Facebook client SDK for authentication:

client.login(
     "facebook",
     {"access_token": token})
.done(function (results) {
     alert("You are now logged in as: " + results.userId);
}, function (err) {
     alert("Error: " + err);
});

This example assumes that the token provided by the respective provider SDK is stored in the token variable.

Microsoft Account example

The following example uses the Live SDK, which supports single-sign-on for Windows Store apps by using Microsoft Account:

WL.login({ scope: "wl.basic"}).then(function (result) {
      client.login(
            "microsoftaccount",
            {"authenticationToken": result.session.authentication_token})
      .done(function(results){
            alert("You are now logged in as: " + results.userId);
      },
      function(error){
            alert("Error: " + err);
      });
});

This example gets a token from Live Connect, which is supplied to your App Service by calling the login function.

How to: Obtain information about the authenticated user

The authentication information can be retrieved from the /.auth/me endpoint using an HTTP call with any AJAX library. Ensure you set the X-ZUMO-AUTH header to your authentication token. The authentication token is stored in client.currentUser.mobileServiceAuthenticationToken. For example, to use the fetch API:

var url = client.applicationUrl + '/.auth/me';
var headers = new Headers();
headers.append('X-ZUMO-AUTH', client.currentUser.mobileServiceAuthenticationToken);
fetch(url, { headers: headers })
    .then(function (data) {
        return data.json()
    }).then(function (user) {
        // The user object contains the claims for the authenticated user
    });

Fetch is available as an npm package or for browser download from CDNJS. You could also use jQuery or another AJAX API to fetch the information. Data is received as a JSON object.

How to: Configure your Mobile App Service for external redirect URLs.

Several types of Apache Cordova applications use a loopback capability to handle OAuth UI flows. OAuth UI flows on localhost cause problems since the authentication service only knows how to utilize your service by default. Examples of problematic OAuth UI flows include:

  • The Ripple emulator.
  • Live Reload with Ionic.
  • Running the mobile backend locally
  • Running the mobile backend in a different Azure App Service than the one providing authentication.

Follow these instructions to add your local settings to the configuration:

  1. Log in to the Azure portal
  2. Select All resources or App Services then click the name of your Mobile App.
  3. Click Tools
  4. Click Resource explorer in the OBSERVE menu, then click Go. A new window or tab opens.
  5. Expand the config, authsettings nodes for your site in the left-hand navigation.
  6. Click Edit
  7. Look for the "allowedExternalRedirectUrls" element. It may be set to null or an array of values. Change the value to the following value:

      "allowedExternalRedirectUrls": [
          "http://localhost:3000",
          "https://localhost:3000"
      ],
    

    Replace the URLs with the URLs of your service. Examples include "http://localhost:3000" (for the Node.js sample service), or "http://localhost:4400" (for the Ripple service). However, these URLs are examples - your situation, including for the services mentioned in the examples, may be different.

  8. Click the Read/Write button in the top-right corner of the screen.
  9. Click the green PUT button.

The settings are saved at this point. Do not close the browser window until the settings have finished saving. Also add these loopback URLs to the CORS settings for your App Service:

  1. Log in to the Azure portal
  2. Select All resources or App Services then click the name of your Mobile App.
  3. The Settings blade opens automatically. If it doesn't, click All Settings.
  4. Click CORS under the API menu.
  5. Enter the URL that you wish to add in the box provided and press Enter.
  6. Enter additional URLs as needed.
  7. Click Save to save the settings.

It takes approximately 10-15 seconds for the new settings to take effect.

How to: Register for push notifications

Install the phonegap-plugin-push to handle push notifications. This plugin can be easily added using the cordova plugin add command on the command line, or via the Git plugin installer within Visual Studio. The following code in your Apache Cordova app registers your device for push notifications:

var pushOptions = {
    android: {
        senderId: '<from-gcm-console>'
    },
    ios: {
        alert: true,
        badge: true,
        sound: true
    },
    windows: {
    }
};
pushHandler = PushNotification.init(pushOptions);

pushHandler.on('registration', function (data) {
    registrationId = data.registrationId;
    // For cross-platform, you can use the device plugin to determine the device
    // Best is to use device.platform
    var name = 'gcm'; // For android - default
    if (device.platform.toLowerCase() === 'ios')
        name = 'apns';
    if (device.platform.toLowerCase().substring(0, 3) === 'win')
        name = 'wns';
    client.push.register(name, registrationId);
});

pushHandler.on('notification', function (data) {
    // data is an object and is whatever is sent by the PNS - check the format
    // for your particular PNS
});

pushHandler.on('error', function (error) {
    // Handle errors
});

Use the Notification Hubs SDK to send push notifications from the server. Never send push notifications directly from clients. Doing so could be used to trigger a denial of service attack against Notification Hubs or the PNS. The PNS could ban your traffic as a result of such attacks.

More information

You can find detailed API details in our API documentation.