30 Days of Zumo.v2 (Azure Mobile Apps): Day 9 – Table Controller Operations

I introduced the table controller in my last article and showed off all the things you can do in defining tables at the table level. All the settings are common across all operations to the table. This includes schema and authorization settings. Today, I am looking at individual operations. A table controller provides an OData v3 data source with GET, POST, PUT and DELETE operations.

The per-operation settings

There are four operations on a table, corresponding to the four operations in a typical CRUD controller:

  • CREATE is table.insert
  • READ is table.read
  • UPDATE is table.update
  • DELETE is table.delete

There is also a table.undelete() – this is a special case of a POST with an ID to undelete a previously deleted record. Soft delete must be enabled for this option. If you want to set an option on the READ operation, you would set it on table.read, for example. Let’s look at some:

Per-Operation Access Control

Last time, I showed you how to specify the default access control: something like this:

var table = require('azure-mobile-apps').table();

table.access = 'authenticated';

module.exports = table;

You can also specify access control on a per-operation basis. For example, let’s look at a read-only table:

var table = require('azure-mobile-apps').table();

table.access = 'disabled';
table.read.access = 'anonymous';

module.exports = table;

Note that I specify the default permission using the table.access, then override it with individual operation access permissions. Another common pattern would be the ability to read anonymously, but only update when authenticated:

var table = require('azure-mobile-apps').table();

table.access = 'authenticated';
table.read.access = 'anonymous';

module.exports = table;

Yet another option would be a table where you can’t delete or update anything – only insert into the table:

var table = require('azure-mobile-apps').table();

table.access = 'authenticated';
table.update.access = 'disabled';
table.delete.access = 'disabled';

module.exports = table;

In all cases, the same logic as for table.access applies:

  • ‘authenticated’ requires the submission of a valid X-ZUMO-AUTH token – respond with 401 Unauthorized if not validly authenticated.
  • ‘anonymous’ allows anyone to perform the operation
  • ‘disabled’ means that the server responds with 405 Method not allowed

Per-operation Middleware

You can also define a method of executing some additional code during the execution of the operation. I’ve already shown an example this when I was demonstrating the personal table – obtaining the email address so that I can use it in my table. The general form here is:

var table = require('azure-mobile-apps').table();

table.access = 'authenticated';

table.read(function (context) {
    // Pre-operation tasks

    return context.execute().then((response) => {
        // Post-operation tasks

module.exports = table;

Common pre-operation tasks are authorization, query adjustment and field insertion. I showed off examples of the latter two in the Personal Tables article – query adjustment to only show records that belong to the authenticated user and field insertion to insert the users email address. I’ll cover authorization in another article.

The Operation Context

When the operation middleware is called, a context is passed. The context has the following properties:

Property Type Usage
query queryjs/Query The query to be executed
id string The record ID
item object The inbound record
req express.Request The request object
res express.Response The response object
data data The data provider
push notification hub The push provider
logger winston The logger provider
tables function Accessor for tables
table object The current table
user object The authenticated user
execute function Execution function

The query, id and item properties are used in various operations:

Property Used in
query read (search), update
id read (fetch), delete
item insert, update

The req and res options are from the express object – you can use these to access other headers and cookies or directly manipulate the response. Most of the other properties allow you to access pre-configured services. I’ve already introduced the user object – the only thing guaranteed there is the user.id value – everything else is optional, although the user object also has a getIdentity() method. Finally, we get to the execute() method. This executes the query and returns a Promise that resolves (eventually) to the response. However, that doesn’t stop you from altering the response as you go.

Let’s take a quick look at an example. Let’s say we adjust our existing TodoItem.js script like this:

// READ operation
table.read(function (context) {
  console.log('context.user = ', JSON.stringify(context.user));
    return context.user.getIdentity().then(function (userInfo) {
        console.log('userInfo.aad.claims = ', JSON.stringify(userInfo.aad.claims));
        context.query.where({ userId: userInfo.aad.claims.emailaddress });
        return context.execute();
    }).then(function (response) {
        console.log('read.execute response = ', response);
        return response;

All this code does is print out the response to the log. You’ll need to turn on application logging at a verbose level to view this. When you do (and run your application), here is what you will see:


The response in this case (for a read/search) is an array of results. We can use this fact to do some sort of business logic.

Business Logic like what?

Well, we’ll get into some very specific things dealing with Push Notifications later on in the course. However, some things could be to asynchronously kick off a queue submission. As a quick example, let’s say you are using the Azure Storage API to store images. Once the image is stored, you update the database with a unique ID and some meta-data on the image. But you want to add a watermark, resize the image, or notify someone that an image is available for review. You could do this in a post-execute phase.

Next Steps

Middleware is an incredibly powerful functionality that allows you to do pre- and post-processing on requests on a per-operation basis. The last two articles have been just introducing the table controller functionality. In the next article, I’m going to use this functionality to provide authorization capabilities to my operations in a way that, hopefully, can be considered somewhat boilerplate. Until then, you can find todays code at my GitHub Repository.

2 thoughts on “30 Days of Zumo.v2 (Azure Mobile Apps): Day 9 – Table Controller Operations

  1. Adrian, Thanks for this series. Trying to follow along, but ran into issues straight away. Tried to comment on Day2, but comments are closed. My issue has to do with setting up for offline local dev. I get sqlite3 not found among other things. I asked for help here:

    Thanks. Josh


    • Hey Josh – I’ve got the developer looking at your issue and he will reply to the MSDN Forums post. Once I see what the answer is, I’ll incorporate an update into the Day 2 post.


Comments are closed.