Azure MobileApp データ同期メモ

# Azure MobileApp データ同期メモ

ちょっとMobileAppをデータ同期の機能まわりの使い方を調べつつ備忘録。

# クイックスタート

## 作成

![create-mobileapp.png](https://qiita-image-store.s3.amazonaws.com/0/246831/260fe239-9938-0825-a744-86a1fd623c53.png)

ポータルから作成→Mobile App Quickstartで作成。"Mobile App" と "Mobile App Quickstart" の違いはからTodoアプリがデプロイされているかどうかです。変更は簡単なのでとりあえず Quickstart で作ってしまえばよいでしょう。

## データベース接続の追加

作成時点で既に SQLite をバックエンドとして設定済み、TodoItemテーブル作成済みです。

![mobileapp-dataconnection.png](https://qiita-image-store.s3.amazonaws.com/0/246831/859d04ed-bcb2-5f72-b198-94ae652d14af.png)

クイックスタートの 1 データベースの接続 からデータ接続を追加すると、SQL Databaseにバックエンドを変更可能です。
EasyTables から現在のバックエンドのテーブルスキーマを確認可能です。

## バックエンドのソースコード確認

クイックスタート作成時点で [Todoアプリのサーバ](https://github.com/Azure/azure-mobile-apps-quickstarts/tree/master/backend/node/TodoSample)が既にデプロイされています。
とりあえずこいつをベースに改造していく事にします。

## クライアントアプリの実行

クイックスタートからTodoアプリのソースがそのままダウンロードできます。
一番手軽に試せる Xamarin.Forms用を選択して実行してみます。

![todoapp.png](https://qiita-image-store.s3.amazonaws.com/0/246831/56dc12e1-faae-082f-7863-a5ba92a5b44c.png)

![todo-db.png](https://qiita-image-store.s3.amazonaws.com/0/246831/817c1ec2-f601-a043-59e2-21cfc9fc9956.png)

Todo に買い物リストを適当追加して、DBも覗いてみます。
これだけでちゃんと動いていますね。

# ユーザ個別データ

さて、ここからが本題。
とりあえず Todoアプリは動きましたが、これでは全ユーザが同じ Todo を共有してしまう事になります。これをユーザごとのデータを持って同期するようにしたいです。

[サーバSDKのドキュメント](https://docs.microsoft.com/ja-jp/azure/app-service-mobile/app-service-mobile-node-backend-how-to-use-server-sdk#howto-tables-getidentity)にはひっそりと認証を構成してリソースへのアクセスを制限する方法が書いてあるのでこいつに従って作業していく事にします。

## 認証の構成

何はなくとも認証が必要なので追加していきます。

### サーバ側

[ドキュメント](https://docs.microsoft.com/ja-jp/azure/app-service-mobile/app-service-mobile-auth)に従って認証を追加していきます。

![setup-auth.png](https://qiita-image-store.s3.amazonaws.com/0/246831/e11e07e3-32cf-9099-80b8-76b416025d05.png)


ここではとりあえず Google を足してみました。Google Developer Console からアプリを追加し、Google+ API を有効にして OAuth認証情報を作成し、クライアントIDとシークレットをコピーしてきて認証を構成します。

### クライアント側

[ドキュメント](https://docs.microsoft.com/ja-jp/azure/app-service-mobile/app-service-mobile-xamarin-forms-get-started-users)に従って認証を追加していきます。

![uwp-regist-manifest.png](https://qiita-image-store.s3.amazonaws.com/0/246831/247c8a63-90ff-c012-0ccd-523373595819.png)


リダイレクト用のスキームを登録します。UWPの場合、アプリケーションのマニフェストにプロトコルを追加し、とりあえず表示名と名前(プロトコル名)だけ設定してしまいましょう。
プロトコルを登録する為に一旦アプリを起動・終了し、Windowsのファイル名を指定して実行あたりから "プロトコル名://" と叩いてアプリが起動すればOKです。

![regist-redirect-uri.png](https://qiita-image-store.s3.amazonaws.com/0/246831/52d58f15-0600-b461-564c-73c1763c9002.png)


そして、サーバ側の設定に戻って "プロトコル名://easyauth.callback" を許可されたリダイレクトURL に追加します。
続けてドキュメントの通りに認証のコードを追加すると、サインインの機能が追加されます。

![uwp-sign-in.png](https://qiita-image-store.s3.amazonaws.com/0/246831/1825797c-5600-2c0d-a050-0ba2f4dbf66e.png)


"+"ボタンの横に"Sign-in"ボタンが表示され、押すとブラウザが立ち上がってサインインフローが開始します。DBとの同期のタイミングが変更され、同期のタイミングはサインイン成功後に変わります。
ただ、ここまでの作業ではあくまでアプリ認証の機能が追加されただけであり Todoには依然全てのTodoが表示されています。

## ユーザごとにリソースへのアクセス制限

### DBスキーマ変更

![modify-easy-table.png](https://qiita-image-store.s3.amazonaws.com/0/246831/e9f76cc2-a258-0880-a597-4b0becd5f3d6.png)


ポータルのEasyTablesからスキーマ→列の追加を選択し、userId列を追加します。

### DBアクセスメソッドの変更

サンプルの TodoItem.js はユーザごとにリソースへのアクセス制限のコードがコメントアウトされた形で記述されています。
コメントを外してサーバを更新します。

```js:TodoItem.js
// Configure specific code when the client does a request
// READ - only return records belonging to the authenticated user
table.read(function (context) {
  context.query.where({ userId: context.user.id });
  return context.execute();
});

// CREATE - add or overwrite the userId based on the authenticated user
table.insert(function (context) {
  context.item.userId = context.user.id;
  return context.execute();
});

// UPDATE - for this scenario, we don't need to do anything - this is
// the default version
table.update(function (context) {
  return context.execute();
});

// DELETE - for this scenario, we don't need to do anything - this is
// the default version
table.delete(function (context) {
  return context.execute();
});
```

サーバを更新し、クライアントを起動してサインインすると今度はリストが空になります。最初に追加したデータは userId=null でサインインしているユーザのデータではないからですね。

![todo-per-user-db.png](https://qiita-image-store.s3.amazonaws.com/0/246831/b5527006-d688-65a8-959a-390ba9b09626.png)

この状態でデータを追加し、DBを確認すると userId列が入っていてユーザごとのデータになっている事が確認できます。

# オフライン同期・読み取り専用データ

お次はデータのオフライン同期とクライアントの更新不可。
なぜ一緒かというと全ユーザに共通なマスタデータのようなものをMobleAppで管理して、サーバ側での変更に自動で同期させる機能を想定しているからです。
非常に簡単なのでセットで行きます。

## 読み取り専用データ

![modify-permission.png](https://qiita-image-store.s3.amazonaws.com/0/246831/4725191a-d125-af6f-ca37-d6999d66c8af.png)

ポータルのEasy Tablesからスキーマ→アクセス許可の変更を行い、読み取りアクセス以外を無効にするだけ。
アクセスしようとすると403が発生するようになります。

## オフライン同期

こちらはクライアント側ソースの変更。サンプルだと #define OFFLINE_SYNC_ENABLED で切り替えが可能なのでコメントアウトするだけ。
ただ、更新通知のようなものはオンライン含めありませんのでそのへんは何か工夫して自分で実装する必要がありそうです。

# まとめ

なかなか使い勝手は良さそうですね。中身は AppService みたいなので C# で作ったサーバに外付けでデータ同期用のエンドポイントを追加したりもできそうですが、データ同期対象のデータ専用にゆるく node.js でサーバを立てて使うのも良いのではないでしょうか。