An amazingly simple solution for Mobile Apps to sync with the Cloud using Change Tracking API
Tags: webdev, beginners, sql, programming
Published: 2020-03-04 17:13:05

If you are creating a mobile app that will work sending data back and forth from the cloud (I guess that 99% of the apps fall into this use case), you will have at some point the need to sync data between the app and the cloud itself.

> If you are a code-first person, grab it right away here: [Using Azure SQL Change Tracking API to Sync mobile Apps data with the Cloud](https://github.com/Azure-Samples/azure-sql-db-sync-api-change-tracking)

This may be needed for several reasons, here's a few:

1. The app also offer a desktop or website experience and data can be managed from there too
2. The app was not connected to the cloud for a while and some data processed in the cloud needs to be sent to the app
3. A user freshly installed the app on a new device and of course now he/she want to see not only the new data but also the preexisting one

Let's see the process a bit more in detail and let's also generalize a bit so we can came up with a solution that will work on all possible situations.

{% youtube c1BmNruu6wc %}

# App to Cloud Sync

Synchronizing changes done on the app while it was offline is the easiest part. Figuring out what data has been created, changed or deleted in the application while it was offline is quite easy. Those changes are done directly from the application, so it has knowledge of them. You just need to make sure you keep track of those changes, for example put them in a queue, so that they can be sent to the cloud as soon the connectivity is back.

> On a mobile device, you never know if connectivity will be available

There is nothing new here, as the concept of *Connection Resiliency* should be quite familiar to all mobile developers. On a mobile device, you never know if connectivity will be available or the endpoint you need to call will there to answer your requests. So you need to code defensively, making sure retry logic and requests queuing is something your application implements correctly. As I'm more experienced with C#, I'm aware of frameworks like Polly and resources like the following:

. https://github.com/reactiveui/Akavache
. https://robgibbens.com/resilient-network-services-with-xamarin/
. http://www.thepollyproject.org/

I'm pretty sure there are many resources around this topic, for all the major mobile platform and languages. I'm definitely not a Mobile developer, so if you have any comments or resource to share, please do :).

# Cloud to App Sync

Sending data from the cloud to the app is way more tricky. You want to do it in the most efficient way, to spare bandwidth and device battery life, so you need a way to know what has changed since the last time that specific user *and device* synced. As data is surely stored in a database of some sort, you also need some efficient method on the database side to make sure you can quickly get everything that is new or changed and that is in the scope for that specific user/device. If your mobile application is successful, this means that you may literally have millions and millions of rows or documents to scan and check for changes.

Not an easy task: all hope is lost then? Just send back the whole data set and that's it? Of course not! We don't want to just be developers, but _better_ developers, right?

Modern databases can help a lot in tackling this challenge. Azure SQL, for example, has a feature called **Change Tracking** that, guess what?, will take care of keeping track of changes for you.

Here's a very high level of how it works:

![Sync Explained](https://dev-to-uploads.s3.amazonaws.com/i/csk846r0e2dfdfhl1b20.PNG)

But let's dive into it a bit deeper, to see how it can help us creating a nice API that, when called, will return all the data that has been inserted, updated or deleted since the last time it such API was called from a user/device.

## The sample scenario

Imagine that you are creating an application to track your Running Sessions (Yep, that's exactly what I was doing before joining Microsoft: https://www.sensoriafitness.com/). Many people loves running, hiking or cycling, so you are surely aware of application like Runtastic, Strava and the likes. 

### First Sync

The first time your application starts after being installed, it will need to query the server, (once the user has logged in), and download all the existing data for that user. 

```
curl -s -k --url https://localhost:5001/trainingsession/sync
```

Here's the JSON you may expect to receive from the *sync* REST endpoint:

```
{
  "Metadata": {
    "Sync": {
      "Version": 123,
      "Type": "Full"
    }
  },
  "Data": [
    {
      "Id": 10,
      "RecordedOn": "2019-10-27T17:54:48-08:00",
      "Type": "Run",
      "Steps": 3450,
      "Distance": 4981,
      ...
    },
    { 
      "Id": 11,
      "RecordedOn": "2019-10-26T18:24:32-08:00",
      "Type": "Run",
      "Steps": 0,
      "Distance": 4562,
      ...
    }
  ]
}
```

The JSON document has two sections. The _Metadata_ section will tell you if you are receiving the _Full_ set of data or just the change set, and an identifier of the version of data you are receiving. In the above sample, we are receiving a _Full_ set, that comes with the version number 123. This number has no special meaning: it just represent a number associated with the _current_ version of data. Is a way, for us, that we'll use in future to tell the server that we won't need all that data again, since version 123 it's our starting point. In a hypothetical timeline, this is our "T0", the start of our timeline. We'll just need to get the changes from there and on.
The _Data_ section contains all the data we need to use to populate our application so that it will show all past Running sessions. Nothing complex here. You may literally save that part of the JSON as is, and use it in your app. I think it will still be better to save it into something like [SQLite](https://www.sqlite.org/index.html), but that's up to you.

### Subsequent Syncs

The users loves our application and they keep using it. We also created a nice website where they can play with their data, slicing and dicing to analyze their performances, adding title and notes to their sessions, and using some clever AI service to analyze their performance and get a customized plan to improve in specific areas. Of course, some of the processing needs to be done on the cloud and the sent back to the app. So the app needs to sync again, this time not to send new sessions, but to _get_ updates from the cloud.

This is what it can expect to receive, exactly from the same _sync_ endpoint it called before. This times the app call the REST endpoint sending also the version number it has received before: 123. 

```
curl -s -k -H "fromVersion: 123" --url https://localhost:5001/trainingsession/sync
```

The answer will be something like this:

```
{
  "Metadata": {
    "Sync": {
      "Version": 201,
      "Type": "Diff"
    }
  },
  "Data": [
    { 
      "$operation": "U",
      "Id": 11,
      "RecordedOn": "2019-10-26T18:24:32-08:00",
      "Type": "Run",
      "Steps": 4346,
      "Distance": 4562,
      ...
    },
    {
      "$operation": "I",
      "Id": 67,
      "RecordedOn": "2019-10-28T17:19:47-08:00",
      "Type": "Run",
      "Steps": 4866,
      "Distance": 4671,
      ...
    }
  ]
}
```

The server is sending us only a _Diff_ data set, which contains all the changes we need to apply locally, to move the version we have, 123, to become the same as the current data, which is represented by the new version number, 201.

Within the _Data_ section, there is a new element, _$operation_, that tell us if that data must be **I**nserted, **U**pdated, or **D**eleted, so that, if we'll apply all changes to local data (version 123) it will become the same as the current data on server (version 201).

It's up to us to apply the received data, with the specified operations, to our local data set, as how those changes will be applied depends on the technology we decided to use to store our data locally.

## Wouldn't it be nice...

...if the generation of the JSON, the decision if a row must be inserted, updated or delete, can be done by the database for us? We just pass the starting version to the database, which it will check the difference against the current version and...well, done.

Yes, it would be nice. No, better, it would be *amazing*...because figuring out what are the changes to be sent to each different user/device is really not a simple task. 

Let me explain why with a simple example: for `UserA/Device1`, it might be that some data doesn't even need to be sent at all, because, since its last sync, that data was inserted and then deleted, so there is no point in sending it at all. But maybe for `UserA/Device2` things are different. Let's say it was synced after the insert but before the subsequent delete of the same document...as you can guess, `UaerA/Device2` only needs to be acknowledged of the delete operation. 

Now imagine a lot of users and a lot of devices. How time consuming doing something like that could be? Yeah, **very** time consuming. 

Well, luckily for us Azure SQL does exactly this. Change Tracking is an amazing technology that will make everything I just explained as easy as:

```sql
select 
	ct.SYS_CHANGE_OPERATION as '$operation',
	ct.Id, 
	ts.RecordedOn,
	ts.[Type], 
	ts.Steps, 
	ts.Distance
from 
	dbo.TrainingSession as ts 
right outer join 
	changetable(changes dbo.TrainingSession, @fromVersion) as ct on ct.[Id] = ts.[id]
```

The `changetable` operator will take care of everything for you, exactly as we dreamed of. Just pass in the version you want to sync from, and it will give you all the operations you need to do to sync with the _current_ version, whatever it is.

Now, we're all developers here....so we really don't want to deal with tables, rows and all that stuff. How to turn that into JSON? 

We learned how to do that in the previous articles. This time is a bit (just a bit, I promise!) more complex as we want to create a JSON like we discussed before, and we don't want to use the JSON as it comes out from Azure SQL.

Azure SQL allows to define the JSON in exact shape you need, thanks to FOR JSON PATH:

```sql
select
	@curVer as 'Metadata.Sync.Version',
	'Diff' as 'Metadata.Sync.Type',
	[Data] = json_query((
		select 
			ct.SYS_CHANGE_OPERATION as '$operation',
			ct.Id, 
			ts.RecordedOn,
			ts.[Type], 
			ts.Steps, 
			ts.Distance
		from 
			dbo.TrainingSession as ts 
		right outer join 
			changetable(changes dbo.TrainingSession, @fromVersion) as ct 
			on ct.[Id] = ts.[id]
		for 
			json path
	))
for
	json path, without_array_wrapper
```

Isn't that amazing? Just think to how many hours of work you have just saved!

# See it in action!

If you are interested and want to see that in action yourself, you can find a working sample where:

https://github.com/Azure-Samples/azure-sql-db-sync-api-change-tracking

you'll be able to deploy it in minutes. 

![A working sample](https://dev-to-uploads.s3.amazonaws.com/i/jgngpt8a030y6hoiyf1x.png)

Everything is done in C#, but doing it in Python should be quite simple, as you can start from here:

[Building REST API with Python, Flask and Azure SQL ](https://dev.to/azure/building-rest-api-with-python-flask-and-azure-sql-18p4)

and make the few required changes.

Enjoy!