2015 年 8 月

Volume 30 Number 8

Microsoft Azure Mobile Services - Microsoft Azure Mobile Services: AngularJS 向けの優れたバック エンド

James McCaffrey

AngularJS は、Web とモバイルの両方を対象に JavaScript アプリケーションをビルドするための優れたフレームワークです。非常に強力なフレームワークですが、習得には時間がかかります。着手する前に、ブログや書籍を参考にし、ビデオのコースを視聴して、フォーム、ルーティング、検証などのクライアント側の機能を学習することをお勧めします。残念ながら、クライアント側に関するトピックでは、いつも、バック エンドのことが考えられていないように思えます。ほとんどのラーニング リソースでは、バック エンドについてほとんど取り上げられていません。Angular $httpBackend サービスを中心に説明されているコースもありますが、$httpBackend はテストを目的にプロトタイプをビルドするのに優れた方法です。しかし、運用アプリケーションでデータを保持することは考えられていません。ほかにも、deployd (deployd.com、英語) というオープン ソースの製品が使用されています。この製品では、REST/API バック エンド サーバーが簡単かつ迅速に稼働されます。deployd は無料でダウンロードでき、開発コンピューターやサーバーで実行することができます。これは、REST API のモデル化やテストに適していますが、こちらも運用環境で利用できるかどうかは問題です。運用環境では、REST/JSON サーバーをインターネットに公開して、AngularJS アプリケーションで使用できるようにする必要がありますが、インターネットでのサーバーのホストや管理の作業に手間をかけたくはありません。運用環境では、新しいアプリケーションをすぐに稼働させ、必要に応じて迅速にスケールアップできる必要があります。また、複雑さを増さずにセキュリティ機能を統合できなければなりません。アプリケーション データを格納できるように、REST/JSON の API をセットアップしなければなりません。さらに、こうした問題点すべてを容易に理解して、アプリケーションに盛り込む必要があります。そのため調査を行ったところ、さいわい Microsoft が既にこのような問題点を解決していることがわかりました。そこで、今回は、Microsoft Azure Mobile Services バック エンドと AngularJS フロント エンドとを統合する方法を取り上げます。

Microsoft Azure Mobile Services (AMS) は、まさに、さまざまな機能を盛り込んだバック エンドです。AMS は、運用アプリケーションに必要なバック エンド機能をすべて 1 つにまとめ、以下に示すような魅力的な機能を数多く提供しています。

  • 非常に高速なクラウド ストレージを追加で提供する。
  • REST/JSON を介してアクセスできるテーブルを非常に簡単にビルドできるようにする。
  • Microsoft、Google、Facebook、Twitter など、よく使われているログイン プロバイダーに、組み込みのセキュリティと認証を提供する。
  • 無料で使用を開始でき、需要の多いアプリケーションにはスケール アウトを可能にする。
  • サーバー側の検証を容易にする。
  • JavaScript バック エンドにも .NET バック エンドにも利用可能にする。Microsoft は、AMS サイトのプロビジョニングや、ほぼすべてのクライアント プラットフォームとの統合を非常に容易にしています。

Angular Notes アプリケーション

AngularJS と AMS を接続する方法をデモするために、今回は非常にシンプルな Angular Notes アプリケーションを作成します。これは単一ページのアプリケーションで、メモのリストで構成されます。各メモの隣には削除ボタンを表示します。新しいメモをリストに追加するテキスト ボックスも用意します。図 1 に、Angular Notes アプリケーションの外観を示します。

Angular Notes アプリケーション
図 1 Angular Notes アプリケーション

このアプリケーションでは、Visual Studio 2013 Update 4 と、MSDN の特典として受け取る Azure アカウントを使用します。まず、新しい ASP.NET Web アプリケーションを作成します。オプションを選択していない空のテンプレートを選択します (図 2 参照)。

空の ASP.NET プロジェクトの作成
図 2 空の ASP.NET プロジェクトの作成

ここで、AngularJS ライブラリと Bootstrap ライブラリを追加するため、Angular.Core と Bootstrap の NuGet パッケージを追加します。

初期ビューを作成するには、notes.html という新しい HTML ページをプロジェクトのルートに追加し、図 3 に示すようにこの HTML を変更します。この HTML では、Angular と Bootstrap を参照しているのがわかります。また、Angular にこのページを処理するように指示する ng-app タグもあります。最後に、後ほどビルドするコントローラー用に ng-controller タグを設定した body セクションがあります。見栄えを良くするために、Bootstrap クラスの配置も多少行っています。Bootstrap クラスは必須ではないので無視してもかまいません。

図 3 初期の HTML ビュー

<html ng-app="notesApp">
<head>
  <title>Angular Notes</title>
  <link type="text/css" rel="stylesheet" href="Content/bootstrap.css" />
  <script src="Scripts/angular.js"></script>
  <script src="notesCtrl.js"></script>
</head>
<body ng-controller="notesCtrl as vm">
  <div class="page-header text-center">
    <h1>
      <span class="glyphicon glyphicon-cloud" aria-hidden="true"></span>
      <span style="padding-bottom:10px">Angular Notes</span>
    </h1>
  </div>
</body>
</html>

メモのリストを追加するには、body セクションの内側の一番下に、新しい div を追加します (図 4 参照)。この div は、メモのリストをループして、テーブル行をそれぞれ表示します。各行には削除ボタンも配置します。このための重要なのは ng-repeat タグで、コントローラーの notes 配列全体をループします。

図 4 メモのリストの追加

<div class="container">
  <div class="panel panel-default">
    <table class="table table-striped">
      <tr class="list-group" ng-repeat="note in vm.notes">
        <td>
          {{note.notetext}}
          <button class="btn btn-xs btn-danger pull-right"
            ng-click="vm.deleteNote(note)">
            <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
          </button>
        </td>
      </tr>
    </table>
  </div>
</div>

最後に新しいメモを入力するボックスを作成するため、ビューの最後に div を 1 つ追加します。これで、ユーザーは新しいメモを作成できるようになります。この div を notes テーブルの div の上に配置します。以下のコードでは、入力ボックスのコンテンツを vm.addNoteText にデータ バインドし、ボタンのクリックや Enter キーの押下で、コントローラーの vm.addNote メソッドが呼び出されるようにしています。

<div class="input-group" style="padding-bottom:15px">
  <input type="text" class="form-control" ng-model="vm.addNoteText"
    placeholder="new note" ng-keypress="($event.which === 13)?vm.addNote():0" />
  <span class="input-group-btn">
    <button ng-click="vm.addNote()" class="btn btn-success">Add Note</button>
  </span>
</div>

コントローラーを追加するには、notesCtrl.js という新しい JavaScript ファイルをプロジェクトのルートに作成します。図 5 に、コントローラー全体のコードを示します。コントローラー全体のコードは、表示する初期 notes 配列、配列に項目を追加する addNote 関数、および配列からメモを削除する deleteNote 関数で構成されます。このスクリプトへの参照を notes.html ビューに必ず含めるようにします。

図 5 コントローラーの追加

angular.module('notesApp', [])
  .controller('notesCtrl', function () {
    var vm = this;
    vm.addNoteText = '';
    vm.notes = [
      { "notetext": "Fix driveway" },
      { "notetext": "Replace roof" },
      { "notetext": "Fix dryer" },
      { "notetext": "Tear out deck" },
      { "notetext": "Add electricity to garage" }
    ];
    vm.addNote = function () {
      if (vm.addNoteText !== '') {
          vm.notes.push({ "notetext": vm.addNoteText });
          vm.addNoteText = '';
      }
    }
    vm.deleteNote = function (note) {
      vm.notes.splice(vm.notes.indexOf(note), 1);
    }
  });

これで、核となる Angular アプリケーションは完成です。ページを実行すると、メモのリストが表示されます。メモの隣にある赤の [X] ボタンを押すと、そのメモが削除されます。テキスト ボックスに新しいメモを入力して、[Add Note] をクリックすると、入力したメモがリストに追加されます。ここまでは順調ですが、リストはメモリ内にのみに存在します。ページを最新の情報に更新すると、オリジナルのリストが再表示され、すべての変更が失われます。変更が失われるのを防ぐには、データ ストレージをメモリからクラウドに移動します。

Microsoft Azure Mobile Services でのデータの格納

ここでは、メモの格納メカニズムを変更します。静的なメモリ内配列を使用するのではなく、AMS を使用してメモの読み込みと保存を行います。

Microsoft Azure ポータルで、新しい AMS を作成します。今回は JavaScript バック エンドを使用します。次に、モバイル サービス内の [データ] タブをクリックして、データ テーブルを新しく作成します (図 6 参照)。

Notes テーブルの新規作成
図 6 Notes テーブルの新規作成

次に、メモのテキスト列を追加するため、notes テーブルに notetext という文字列型の列を追加します。

ここで、アプリケーション キーの入手が必要になります。Microsoft Azure ポータルの AMS のメイン ページに [キーの管理] ボタンがあります。このボタンをクリックしてアプリケーション キーを取得し、後で使用できるように保存します。Angular アプリケーションから AMS に接続するためにこのキーが必要になります。

Angular アプリケーションで AMS を機能させるには、Notes.html ビューに 2 つのスクリプト参照を追加する必要があります。1 つは、AMS 用に Microsoft が提供する JavaScript ライブラリ用のスクリプト参照です。もう 1 つは、Microsoft ライブラリをラップする Angular 形式のサービスへのスクリプト参照です。このライブラリの主なメリットは、AMS 用に Microsoft JavaScript ライブラリを拡張して、Angular 形式のインターフェイスやプロミスを提供することです。このライブラリの優れたサンプル コードは、GitHub (bit.ly/1po76vI、英語) からダウンロードできます。

以下に示すように、これらの新しいエントリが angular.js 参照と notesCtrl.js 参照の間に配置されます。

<script src="Scripts/angular.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/mobileservices/MobileServices.Web-1.1.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-azure-mobile-service/1.3.4/angular-azure-mobile-service.min.js"></script>
<script src="notesCtrl.js"></script>

コントローラーで AMS を参照するには、NotesCtrl.js の最初の行を変更して、'azure-mobile-service.module' との依存関係を追加します。

angular.module('notesApp', ['azure-mobile-service.module'])

notesCtrl.js ファイルの一番下に、Microsoft Azure モバイル サイトの URL と先ほど取得したアプリケーション キーを指定する定数を追加します。AMS ライブラリは、この定数を使用して AMS サイトにアクセスすることになります。

angular.module('notesApp').constant('AzureMobileServiceClient', {
  API_URL: "https://angularnotes.azure-mobile.net/",
  API_KEY: "gkwGJioLD3jNxrAX6krXh6jVk6SFkeQr",
});

ここで、vm.notes に静的配列を設定するコントローラーのコードを置き換え、AMS からデータを取得するようにします。そのためには、notes テーブル全体を取得して、その結果を vm.notes 配列に設定します。

Azureservice.query('notes', {})
.then(function (items)
{
  vm.notes = items;
});

次に、vm.addNote 関数を変更して、新しいメモを notes データ テーブルに保存するようにします。AMS が正常終了を返したら、項目がメモリ内配列に追加されます。これにより、アプリケーションは、項目が追加されるたびにリスト全体を再読み込みする必要がなくなります。

vm.addNote = function () {
  if (vm.addNoteText !== '') {
    Azureservice.insert('notes', {
      "notetext" : vm.addNoteText                 
    }).then(function (newitem) {
      vm.notes.push(newitem);
      vm.addNoteText = '';
    });
  }
}

最後に、vm.deleteNote 関数を変更して、AMS の notes テーブルからメモを削除するようにします。ここでも、AMS が正常終了を返すまで待って、メモリ内配列からそのメモを削除します。

vm.deleteNote = function (note) {
  Azureservice.del('notes', {
    "id": note.id
  }).then(function () {
    vm.notes.splice(vm.notes.indexOf(note), 1);
  });
}

これで、すべてのメモが AMS の notes テーブルから取得されるようになります。ユーザーがメモを追加または削除すると、AMS のデータ テーブルに対して操作が行われます。ごくわずかなコードを記述するだけで、これを実現できます。これは、セットアップと統合が簡単であるという、AMS の大きな強みの 1 つです。

AMS でのユーザーの認証

Web アプリケーションに認証を追加するのは、大変な作業です。独自に認証を作成するかどうかがいつも問題になります。独自に認証を作成しなければならない特別な事情がなければ、最近は、主要 ID プロバイダーのいずれかを利用するのが一般的です。主要 ID プロバイダーは、パスワードの安全な保存やリセットに関する問題に対処しています。AMS では、Microsoft、Facebook、Twitter、Google など、よく使われる ID プロバイダーに簡単に接続できるようにしています。AMS は、ログオン関数と AMS で作成したテーブルによる認証と承認をシームレスに統合します。今回は、認証に Microsoft アカウントを使用することにしました。認証を構成したらサンプル コードを変更して、認証済みのユーザーだけがメモを閲覧または編集でき、独自のリストを表示できるようにします。

まず、Microsoft Live ポータル (bit.ly/1JS4jq3) で今回のアプリケーションをセットアップします。セットアップ時に、AMS が Microsoft の ID 機能を利用するために必要なクライアント ID とクライアント シークレットを取得します。AMS の [ID] タブに取得したクライアント ID とクライアント シークレットを貼り付けます (図 7 参照)。アプリケーションの登録プロセスに関する優れた資料については、https://azure.microsoft.com/ja-jp/documentation/articles/mobile-services-how-to-register-microsoft-authentication/ を参照してください。

Microsoft ID プロバイダーのセットアップ
図 7 Microsoft ID プロバイダーのセットアップ

次に、ログイン ボタンとログアウト ボタンをビューに追加します。以下の div コードを、notes テーブルを含む div タグの上に追加します。

<div class="text-center">
  <button class="btn btn-primary" ng-if="!vm.isLoggedIn()"
  ng-click="vm.login()">Login</button>
  <button class="btn btn-primary" ng-if="vm.isLoggedIn()"
  ng-click="vm.logout()">Logout</button>
</div>

ログイン ボタンの ng-if コードは、ユーザーがログインしていない場合にのみログイン ボタンが表示されるようにしています。ログアウト ボタンの ng-if コードは、ユーザーがログインしている場合にのみログアウト ボタンが表示されるようにしています。

ここで、別の ng-if タグを container というの div に追加して、ユーザーがログインしていない場合はリストと新しいメモ テキスト ボックスを非表示にします。これはセキュリティのためではありません。セキュリティは AMS によって確保されるため、単に、ページの見た目を整えるためです。

<div class="container" ng-if="vm.isLoggedIn()" style="padding:15px">

次に、認証の関数をコントローラーに追加します。isLoggedIn 関数は、ログイン/ログアウト ボタンやメモのリストを表示するか非表示にするかを判断するために、ビューが使用します。この関数は、Azureservice モジュールの isLoggedIn 関数の結果を返すだけです。

vm.isLoggedIn = function ()
{
  return Azureservice.isLoggedIn();
}

アプリケーションの login 関数は、ユーザーがログイン ボタンをクリックすると呼び出されます。この関数は、さらに Azureservice ライブラリの login 関数を呼び出します。メモのリストを AMS にクエリするコードを、コントローラーの先頭からこの関数に移動します。これで、ユーザーの認証が成功した場合のみ、リストが読み込まれるようになります。

vm.login = function () {
  Azureservice.login('microsoftaccount')
  .then(function () {
    Azureservice.query('notes', {})
    .then(function (items) {
      vm.notes = items;
    });
  });
}

logout 関数は、Azureservice モジュールの logout 関数を呼び出すことで、AMS からユーザーをログアウトします。その際、notes 配列をクリアします。

vm.logout = function () {
  vm.notes = [];
  Azureservice.logout();
}

現状、認証されていないユーザーがメモのリスト一を閲覧できないようにする防御策は、ユーザーを認証後にのみメモのリストを読み込むようにするコードのみです。これだけでは安全ではありません。バックエンドで、AMS がこの防御策を講じるようにすることをお勧めします。Microsoft Azure ポータルで、AMS サービスを開いてから、notes テーブルを開き、[アクセス許可] をクリックします。すべてのアクセス許可を [認証されたユーザーのみ] に変更します (図 8 参照)。これで、ユーザーが認証されていない場合、このテーブルへのすべての呼び出しは失敗します。

Notes テーブルのセキュリティ保護
図 8 Notes テーブルのセキュリティ保護

ユーザー データの分離

サイトの認証は機能するようになりましたが、すべてのユーザーは依然として 1 つのリストを共有します。ここで、各ユーザーが自身のメモを表示および編集できるようにします。そのためには、Microsoft Azure ポータルで少し変更を加える必要がありますが、Angular アプリケーションに変更を加える必要はまったくありません。

最初に、notes データ テーブルに移動します。[列] をクリックして、userid という新しい文字列型の列を追加します。これにより、メモとユーザーを関連付けます。次に、notes テーブルの [スクリプト] タブに移動します。[操作] ドロップ ダウン ボックスから [挿入] を選択して、スクリプトに以下のコードを追加します。

function insert(item, user, request) {
  item.userid = user.userId;
  request.execute();
}

この新しいコードは、新しい行の userid に認証プロバイダーの userid を設定します。この処理は、バック エンドのコードで実行する方がはるかに安全です。このコードは Azure で実行されるため、ユーザー (または攻撃者) はこのコードにアクセスできません。

userid によって返されるメモをフィルタリングするには、[操作] ドロップ ダウン ボックスから [読み取り] を選択し、スクリプトを変更します。

function read(query, user, request) {
  query.where({ userid: user.userId });
  request.execute();
}

新しい query.where 行では、ログイン済みユーザーの userid を値として設定した userid 列によって、返される行をフィルタリングします。サーバーでデータをフィルタリングした後にクライアントに送信する方法は、クライアント コードでデータをフィルタリングする場合に比べてはるかに安全です。

これで、Angular Notes アプリケーションは、AMS に注釈を安全に格納できるようになります。また、各ユーザーは、最初に認証されないとアクセスできない個別のメモ リストを保持できるようになります。

まとめ

このデモ アプリケーションでは、ごくわずかなコードを用いて、優れたストレージや認証を提供するクラウドを活用できるようになりました。フロント エンドに AngularJS を採用する場合、バック エンドには Microsoft 製品を利用できないと考えないようにしてください。AMS は AngularJS とシームレスに統合します。AMS は、AngularJS アプリケーション用の優れたバック エンドとして機能します。


Jonathan Miller は、インディアナポリスを拠点とする CuroGens 社のシニア アーキテクトです。10 年以上 Microsoft スタックで製品の 開発しており、.NET のプログラミングに初期のころから携わっています。彼は、フロント エンド テクノロジ (Windows Forms、Windows Presentation Foundation、Silverlight、ASP.NET、AngularJS/Bootstrap)、ミドルウェア (Windows サービス、Web API)、およびバック エンド (SQL Server、Microsoft Azure) を専門とする、フルスタック製品開発者です。

この記事のレビューに協力してくれた技術スタッフの David Crawford (マイクロソフト) と Simon Gurevich (マイクロソフト) に心より感謝いたします。
Simon Gurevich は、現在、Microsoft Consulting Services でプリンシパル コンサルタントを務める、マイクロソフト在籍 15 年のベテランであり、Microsoft Azure プラットフォームのテクノロジを専門にしています。長年、分散アプリケーション アーキテクチャや Microsoft プラットフォームの開発作業の提供に携わっており、近年では、Microsoft Azure の製品グループと密接に連携しています。Microsoft に入社する前は、コンピューター テレフォニーの研究機関で R&D 担当者として勤務しており、膨大なテレフォニー コールのルーティングを行うサーバー ベースのアプリケーションを開発しました。コンピューター サイエンスと数学で修士号を保有しています。