BaaS@rakuza使ってみた

BaaSと言えば国外だったらParse、Firebase、国内だったらニフティクラウド mobile backendなどですが、BaaS@rakuzaというBaaSの記事が無かったので使ってみました。~~（まあ、自社のサービスなんですけど）~~ 
スマホアプリ作成は、HTML/CSS/JSでネイティブアプリが作成できるMonacaを使ってみます。

# BaaS@rakuza申込み
公式サイトから利用申し込みします。（60日無料）
http://www.raku-za.jp/baas/inquiry/
※「無料体験版申し込みはこちら」から
２～３日ほどでテナントキーなどのアカウント情報がメールに送信されます。

# Monaca申込み
Monacaはアカウントは以下から申込みします。とりあえず無料のBasicプランで登録します。
https://ja.monaca.io/

# Monacaプロジェクト作成
「新規プロジェクトの作成」から作成します。OnsenUI2からAngularJS非依存になったため、Vanilla JS（素のJS）、Reactなど、色々なライブラリと組み合わせて使えるようになってます。ただ、クラウドIDEだとAngular2やReactは対応していないので、AngularJS1で作成します。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/51815/f102588f-2968-36b8-4cc2-b353b4542e68.png)

# Cordovaプラグインのインストール
MonacaからBaaS@rakuzaを使用するために、公式が提供しているCordovaプラグインをインストールします。Githubからインポートすることもできますが、Basicプランの場合はCordovaプラグインのインポートができない様なので、クラウドIDEより「Cordovaプラグインの管理...」メニューを開いて、「rakuza」で検索したら候補に挙がるので、有効にしたらOKです。
![無題2.png](https://qiita-image-store.s3.amazonaws.com/0/51815/de0ad815-7894-7d90-8e9a-73f4b8bd17db.png)

# Cordovaプラグインの初期化
`ons.ready()`に登録したコールバック関数にCordovaプラグインの初期化処理を記述します。続いて、上メニューの「ビルド」⇒「Android（iOS）アプリのビルド」からビルド画面を開いて、ビルドを実行。
ビルドできたら、QAコードなどでアプリURLを開いて、実機にインストールします。「初期化成功！」のアラートが表示されたら成功！

```html:index.html
<script>
ons.bootstrap();
ons.ready(function() {
    var tenantKey = "ここにテナントキー";
    RKZClient.setTenantKey(tenantKey, function() {
      alert("初期化成功！");
    }, function(error) {
      // エラー
      alert(JSON.stringify(error, null, " "));
    });
});
</script>
```

# お知らせの作成

試しに、お知らせを表示するアプリを作成してみます。
お知らせの登録はBaaS@rakuzaの管理者機能で行います。

登録した際に送られてきたメールに記載されている管理者画面のURLにアクセスして、「お知らせ管理」⇒「お知らせ一覧」から適当にお知らせを作成します。
![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/51815/991fcee4-863f-6e81-595c-e4bdcd98cb60.png)


# お知らせの表示
登録できたら、クライアント側で表示してみます。index.htmlを以下の様に編集しました。

```html:index.html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <script src="lib/angular/angular.min.js"></script>
  <script src="lib/onsenui/js/onsenui.min.js"></script>
  <script src="lib/onsenui/js/angular-onsenui.min.js"></script>

  <script>
    ons.bootstrap('myApp');
  </script>
  <script src="js/controllers/MainController.js"></script>
  <script src="js/controllers/NewsController.js"></script>
  <script src="js/controllers/NewsDetailController.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body>

<ons-navigator var="navi">
  <ons-page ng-controller="mainController as main">
    <ons-toolbar>
      <div class="center">トップ</div>
    </ons-toolbar>

    <p style="text-align: center">
      <ons-button ng-click="navi.pushPage('news.html');">お知らせ</ons-button>
    </p>
  </ons-page>
</ons-navigator>

<ons-template id="news.html">
  <ons-page ng-controller="newsController as news">
    <ons-toolbar>
      <div class="left">
        <ons-back-button>戻る</ons-back-button>
      </div>
      <div class="center">お知らせ</div>
    </ons-toolbar>

    <div class="progress" ng-if="news.isLoading">
      <ons-progress-circular indeterminate></ons-progress-circular>
    </div>

    <ons-list>
      <ons-list-item ng-repeat="newsDetail in news.news" modifier="tappable" ng-click="news.onSelectNewsDetail(newsDetail)">
        {{newsDetail.title}}
      </ons-list-item>
    </ons-list>
  </ons-page>
</ons-template>

<ons-template id="news_detail.html">
  <ons-page ng-controller="newsDetailController as newsDetail">
    <ons-toolbar>
      <div class="left">
        <ons-back-button>戻る</ons-back-button>
      </div>
      <div class="center">{{newsDetail.newsDetail.title}}</div>
    </ons-toolbar>

    <div style="padding: 16px;">
      <h1>{{newsDetail.newsDetail.title}}</h1>
      <p style="text-align: right;">{{newsDetail.newsDetail.release_end_date | date:'yyyy/MM/dd'}}</p>
      <p>{{newsDetail.newsDetail.description}}</p>
    </div>
  </ons-page>
</ons-template>

</body>
</html>
```

JavaScript側は別ファイルに別けました。以下の感じです。

```js:MainController.js
(function () {
  angular.module('myApp').controller('mainController', MainController);

  /**
   * 主画面のController
   * @constructor
   */
  function MainController() {

    var vm = this;

    ons.ready(onReady);

    ///////////////////

    function onReady() {
      // RKZClientはCordovaPluginのため、「ons.ready」で呼び出す必要がある
      setupRakuza();
    }

    function setupRakuza() {
      // 第一引数で指定されたテナントキーの値をもとに楽座のテナントを設定します
      var tenantKey = 'ここにテナントキー';
      RKZClient.setTenantKey(tenantKey, function() {
        // 成功時の処理
        alert('RKZClientクラスの初期化に成功しました。');
      }, function(error) {
        // エラー時にアラートでエラー内容を表示します
        alert(JSON.stringify(error, null, ' '));
      });
    }

  }

})();
```

```js:NewsController.js
(function () {
  angular.module('myApp').controller('newsController', NewsController);

  /**
   * お知らせ一覧画面のController
   * @constructor
   */
  function NewsController($scope, $timeout) {

    var vm = this;
    vm.onSelectNewsDetail = onSelectNewsDetail;

    ons.ready(onReady);

    ///////////////////

    function onReady() {
      loadNews();
    }

    function loadNews() {
      vm.isLoading = true;

      // BaaS@rakuzaから、上限20件で公開しているお知らせ情報を取得する
      var limit = 20;
      RKZClient.getReleasedNewsList(limit, [], [], function (data) {
        // 成功時の処理
        // BaaS@rakuzaのコールバックは$scope.$applyを呼ばないので、$timeoutで反映を行う
        $timeout(function () {
          vm.news = data;
          vm.isLoading = false;
        });
      }, function () {
        // 失敗時の処理
        alert('エラーが発生しました。');
        $timeout(function () {
          vm.isLoading = false;
        });
      });
    }

    function onSelectNewsDetail(newsDetail) {
      // お知らせ情報を設定して、お知らせ詳細に遷移する
      $scope.navi.pushPage('news_detail.html', { data: newsDetail });
    }
  }

})();
```

```NewsDetailController.js
(function () {
  angular.module('myApp').controller('newsDetailController', NewsDetailController);

  /**
   * お知らせ詳細画面のController
   * @constructor
   */
  function NewsDetailController($scope) {

    var vm = this;

    ons.ready(onReady);

    ///////////////////

    function onReady() {
      // 一覧から渡したお知らせ情報を取得して、ViewModelに設定
      vm.newsDetail = $scope.navi.topPage.data;
      // 日時データは文字列（yyyy-MM-dd HH:mm:ssZ）のため、Date型に変換する
      vm.newsDetail.release_end_date = new Date(vm.newsDetail.release_end_date);
    }
  }

})();
```

AngularJSの話になりますが、RKZClientに渡したコールバック関数は`$scope.$apply`を呼んでくれないので、自分で呼ぶ必要があります。ここでは`$timeout`を使って`$scope.$apply`を呼んでいます。

# 画面
![無題4.png](https://qiita-image-store.s3.amazonaws.com/0/51815/1151a42c-2e5a-f812-f424-441dc384ee1c.png)

# ソースコード
https://github.com/kishino/BaaSSampleApp

# 最後に
私はBaaS@rakuza開発している会社の社員ですが、開発メンバーではなく、Monacaも初めてで、BaaSもあまり使ったことはありません。ですが、結構簡単に環境を作ることができました。
今後もちょくちょく触って、記事を投稿していこうと思います。

# 参考ページ
* [BaaS@rakuzaドキュメント](http://www.raku-za.jp/baas/document/) （HTMLにしてほすぃ）