How to Use the JavaScript client library for Azure Mobile Apps

Overview

This guide teaches you to perform common scenarios using the latest JavaScript SDK for Azure Mobile Apps. If you are new to Azure Mobile Apps, first complete Azure Mobile Apps Quick Start to create a backend and create a table. In this guide, we focus on using the mobile backend in HTML/JavaScript Web applications.

Supported platforms

We limit browser support to the current and last versions of the major browsers: Google Chrome, Microsoft Edge, Microsoft Internet Explorer, and Mozilla Firefox. We expect the SDK to function with any relatively modern browser.

The package is distributed as a Universal JavaScript Module, so it supports globals, AMD, and CommonJS formats.

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.

Installing the Azure Mobile Apps JavaScript SDK can be done via the npm command:

npm install azure-mobile-apps-client --save

The library can also be used as an ES2015 module, within CommonJS environments such as Browserify and Webpack and as an AMD library. For example:

// For ECMAScript 5.1 CommonJS
var WindowsAzure = require('azure-mobile-apps-client');
// For ES2015 modules
import * as WindowsAzure from 'azure-mobile-apps-client';

You can also use a pre-built version of the SDK by downloading directly from our CDN:

<script src="https://zumo.blob.core.windows.net/sdk/azure-mobile-apps-client.min.js"></script>

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.

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 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 sign in with Facebook use the following code:

client.login("facebook").done(function (results) {
     alert("You are now signed 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 sign-in page of the selected provider and generates an App Service authentication token after successful sign-in 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 signed 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.

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 JavaScript applications use a loopback capability to handle OAuth UI flows. These capabilities include:

  • Running your service locally
  • Using Live Reload with the Ionic Framework
  • Redirecting to App Service for authentication.

Running locally can cause problems because, by default, App Service authentication is only configured to allow access from your Mobile App backend. Use the following steps to change the App Service settings to enable authentication when running the server locally:

  1. Log in to the Azure portal

  2. Navigate to your Mobile App backend.

  3. Select Resource explorer in the DEVELOPMENT TOOLS menu.

  4. Click Go to open the resource explorer for your Mobile App backend in a new tab or window.

  5. Expand the config > authsettings node for your app.

  6. Click the Edit button to enable editing of the resource.

  7. Find the allowedExternalRedirectUrls element, which should be null. Add your URLs in an array:

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

    Replace the URLs in the array with the URLs of your service, which in this example is https://localhost:3000 for the local Node.js sample service. You could also use https://localhost:4400 for the Ripple service or some other URL, depending on how your app is configured.

  8. At the top of the page, click Read/Write, then click PUT to save your updates.

You also need to add the same loopback URLs to the CORS allowlist settings:

  1. Navigate back to the Azure portal.
  2. Navigate to your Mobile App backend.
  3. Click CORS in the API menu.
  4. Enter each URL in the empty Allowed Origins text box. A new text box is created.
  5. Click SAVE

After the backend updates, you will be able to use the new loopback URLs in your app.