FJCT_ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

フロントエンドエンジニアの方はぜひ!Dropbox × mBaaSでJavaScriptだけでサーバサイドにデータ保存

最近はWebアプリケーションでローカルのソフトウェアを置き換えてしまおうという試みが多くなっています。画像編集や表計算、ワードプロセッサなど様々にあると思いますが、HTML/JavaScript/スタイルシートだけで作成した場合の問題はデータを保存する場所がないということです。

localStrageを使う方法もありますが、容量が5MBまでの制限があったり、他の人とデータ共有できないという問題があります。そこでぜひ使ってみて欲しいのがニフティクラウド mobile backendのJavaScript SDKです。

JavaScript SDKを組み込めば、それだけでデータをサーバ(mBaaS)に保存できます。今回はその一例としてWebチャットを作ってみました。URLはDropboxのもので、データの保存に際してデータベースを用意していません。もの凄く手軽にWebアプリケーションが作れるようになります。

完成ソース

完成したソースはGitHubにアップロードしてあります。もしうまく動かない場合は参考にしてください。

動作デモ

動作しているデモはこちらで確認できます。URLはDropboxのもので、HTML/JavaScriptのみで動いているのが確認してもらえるかと思います。

用意するもの

ニフティクラウド mobile backendのアカウントを取得する

次にニフティクラウド mobile backendのユーザ登録を行います。もしアカウントを既にお持ちでしたら飛ばしてください。

まず最初にニフティクラウド mobile backendのWebサイトに行きます。そしてログインボタンをクリックします。

そうすると@niftyのログイン画面が表示されます。もし@niftyアカウントをお持ちでしたらログインしてください。お持ちでない場合は下の方にある @nifty会員に新規登録する(無料) をクリックしてください。

こちらは@nifty新規会員登録の画面です。ユーザ名、パスワード、連絡先メールアドレスを入力する必要があります。

入力が終わったらフォームの下にある 登録内容の確認へ をクリックします。

そうすると入力した内容が表示されますので、問題なければ 登録する ボタンをクリックしてください。

登録完了するとこのような画面が表示されます。別途入力してもらったメールアドレス宛に確認メールが送信されていますので、メールアドレス確認処理を行ってください。なお、ニフティクラウド mobile backendへのログインは既に行える状態になっています

初回ログイン

ユーザ登録が終わりましたら先ほどのログインボタンをクリックした画面に戻ります。

@niftyユーザ名、パスワードに先ほど登録したユーザ名、パスワードを入力して ログイン ボタンをクリックしてください。

ログインが成功すると、最初に利用規約が表示されます。内容を確認の上、以上の規約に同意する チェックボックスをつけて アカウント登録 ボタンをクリックしてください。

アカウント登録が終わるとそのままアプリの新規作成画面になります。

アプリ名として使えるのは半角英数字またはアンダースコア(_)になります。例えば今回はNCMBTodoとしています。アプリ名を入力して 新規作成 ボタンをクリックしてください。

アプリが無事作成されると アプリケーションキークライアントキー が生成されます。このキーは後で使いますので画面はこのまま残しておきましょう。もし OK ボタンを押したり、ウィンドウを閉じてしまった場合は 管理画面アプリ設定 の中にAPIキーで確認できます。

署名をサーバサイドで行う

JavaScript SDKの難点としては、初期化するタイミングでアプリケーションキーとクライアントキーを指定しなければならない点です。これは認証として用いていますので漏洩するのは良くありません。そこでHeroku上にサーバを立てて、署名だけサーバサイドで行うようにします。

require 'sinatra'
require 'sinatra/reloader'
require 'openssl'
require 'base64'
require 'json'
set :root, File.dirname(__FILE__)

options '/*' do
  response.headers['Access-Control-Allow-Origin'] = '*'
  response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
end

post '/sign' do
  response.headers['Access-Control-Allow-Origin'] = '*'
  content_type :json
  CLIENT_KEY = 'CLIENT_KEY'
  json = JSON.parse(request.body.read)
  {signature: Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), CLIENT_KEY, json["forEncodeString"])).strip()}.to_json
end

ソースはこれだけです。ニフティクラウド mobile backendのクライアントキーで CLIENT_KEY を置き換えてください。

POST http://example-heroku.herokuapp.com/sign

{"signature":"sG73G2Yh73BeDKJHeB8qIIRH/k+/4ELaSC0jx+nGt3I="}

に署名したい内容を送ると、署名後の文字列を返してくれます。

JavaScript SDKを修正する

署名をサーバサイドで行うのに合わせてJavaScript SDKも修正します。

署名作成を行っている NCMB._createSignature の最後を

var hash = CryptoJS.HmacSHA256(forEncodeString, _clientKey);
var signature = CryptoJS.enc.Base64.stringify(hash);                 
return signature;

から

return NCMB._ajax(
  null,
  null,
  "POST",
  "http://example-heroku.herokuapp.com/sign",
  {forEncodeString: forEncodeString},
  "",
  "");

にします。example-herokuの部分は自分のHerokuアプリに合わせて修正してください。

さらに Ajax処理を行っている NCMB._ajax を修正します。まずヘッダーをニフティクラウド mobile backendの処理時のみにします。

xhr.setRequestHeader("X-NCMB-Application-Key", NCMB.applicationKey );
xhr.setRequestHeader("X-NCMB-Timestamp", timestamp);
xhr.setRequestHeader("X-NCMB-Signature", signature);  

を次のように修正します。

if (url.match(/https:\/\/mb\.api\.cloud\.nifty\.com/)) {
  xhr.setRequestHeader("X-NCMB-Application-Key", NCMB.applicationKey );
  xhr.setRequestHeader("X-NCMB-Timestamp", timestamp);
  xhr.setRequestHeader("X-NCMB-Signature", signature);
}

NCMB._ajaxの返り値でPromiseを使いたいので、

return promise._thenRunCallbacks(options);

return promise;

にします。

そうすると署名処理部分が以下のようにできます。

signature = NCMB._createSignature(route, className, objectId, url, method, timestamp);
var data = dataObject;
return NCMB._ajax(route, className, method, url, dataObject, signature, timestamp)

のようになっていたのが署名処理を非同期化しましたので、

return NCMB._createSignature(route, className, objectId, url, method, timestamp).then(function(response){
  var signature = response.signature;
  return NCMB._ajax(route, className, method, url, dataObject, signature, timestamp).then(null,
    :
});

Promiseを使うことで大きな変更なく実装が進められます。

チャット画面作成

HTMLファイルを作成します。今回はBootstrapを使っています。app.js、logic.jsについては後述します。全体像は次のようになります。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Webチャット</title>
    <link href="//code.htmlhifive.com/h5.css" rel="Latest">
    <!-- stylesheet compiled and minified CSS -->
    <link rel="stylesheet" href="bootstrap.min.css">
    <link href="style.css" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="container">
      <div class="header">
        <ul class="nav nav-pills pull-right">
          <li class="active"><a href="#">Home</a></li>
        </ul>
        <h3 class="text-muted">Webチャット</h3>
      </div>
      <div class="row marketing">
        <div class="col-lg-12">
      <form role="form">
        <div class="form-group">
          <label for="exampleInputEmail1">名前</label>
          <input type="text" class="form-control" id="name" placeholder="名前を入力">
        </div>
        <div class="form-group">
          <label for="exampleInputMessage">発言</label>
          <input type="text" class="form-control" id="word" placeholder="何か適当に入力してくださいな">
        </div>
        <button type="submit" class="btn btn-default submit-button">投稿</button>
      </form>
        </div>
      </div>
      <div class="messages">
      </div>
      <div class="footer">
        <p>&copy; MOONGIFT 2014</p>
      </div>
    </div> <!-- /container -->
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="jquery.min.js"></script>
    <script src="ejs-h5mod.js"></script>
    <script src="h5-1.1.12.dev.js"></script>
    <script src="bootstrap.min.js"></script>
    <script src="ncmb-1.2.2.js"></script>
    <script src="logic.js"></script>
    <script src="app.js"></script>
  </body>
</html>

初期データを取得

今回は hifive というWebアプリケーションフレームワークを使っています。詳細は省きますが、処理としては次のようになります。

app.js
__ready: function() {
  var me;
  me = this;
  return this.chatLogic.getData().done(function(messages) {
    return me.view.append(".messages", 'messages_template', {
      messages: messages
    });
    }).fail(function(data) {
      return console.log('error', data);
    });
  },

初期設定が終わった段階で __ready メソッドが呼ばれます。その中では chatLogic の getData メソッドを実行しています。処理が成功すれば done が呼ばれますので、その中ではテンプレートを使って

の中にHTMLをレンダリングします。

chatLogic.getData メソッドは次のようになります。

MessageClass: function() {
  return NCMB.Object.extend("MessageClass");
},
getData: function() {
  var dfd, query;
  dfd = this.deferred();
  query = new NCMB.Query(this.MessageClass());
  query.descending("createDate");
  query.find({
    success: function(data) {
      return dfd.resolve(data);
    },
    error: function(data) {
      return dfd.reject(data);
    }
  });
  return dfd.promise();
},

処理をPromise化していますが、内容としては ニフティクラウド mobile backend のデータストアで MessageClass を呼び出して、作成日時の逆順(query.descending(“createDate”))でデータを取得しています。処理が成功すれば、Promiseのresolveを呼び出しています。

これだけでニフティクラウド mobile backendへのデータ取得部分が完了になります。

CORS(Cross-Origin Resource Sharing) について

先ほどのデータ取得部分を見ると、POSTメソッドで実行されているのが分かります。通常、外部ドメインのAjax処理はGETメソッドであればJSONPを使って回避できますが、それ以外のメソッド(POST/DELETEなど)は利用できません。

ニフティクラウド mobile backendでは CORS についてドメイン制限を外していますので、POST/DELETEメソッドが自由に使えるようになっています。

新規投稿

Webチャットなので新規投稿も行えないといけません。まずapp.js側を見ていきます。

app.js
".submit-button click": function(context) {
  var me, params;
  context.event.preventDefault();
  me = this;
  params = {
    name: this.$find("#name").val(),
    word: this.$find("#word").val()
  };
  return this.chatLogic.postData(params).done(function(message) {
    return me.view.prepend(".messages", 'messages_template', {
      messages: [message]
    });
  }).fail(function(data) {
    return console.log('error', data);
  });
}

こちらも フォームに入力された名前(id=name)とメッセージ(id=word)をパラメータとして chatLogic.postData を呼び出しているだけです。次にlogic.jsを見てみます。

logic.js
postData: function(params) {
  var dfd, message;
  dfd = this.deferred();
  message = new (this.MessageClass());
  message.set(params);
  message.save({
    success: function(message) {
      return dfd.resolve(message);
    },
    error: function(message, error) {
      return dfd.reject(error);
    }
  });
  return dfd.promise();
}

こちらは実際にニフティクラウド mobile backendへの保存処理を行っています。といっても与えられたパラメータ(名前とメッセージ)をセットして、保存処理(saveメソッド)を呼び出しているだけです。これだけでデータは永続的にクラウド上に保存されます。


完全に個人用途であればJavaScript SDKをそのまま使うこともできるかと思います。外部公開であれば今回のように署名処理をサーバサイドで行い、利用できるドメインを制限するのが良いでしょう。

何よりHTML/JavaScriptだけでサーバサイドにデータを保存し、共有できる仕組みが簡単に構築できてしまうのが魅力ではないでしょうか。データストアはデータベースのように、さらにファイルストアを使えば写真やバイナリファイルをアップロードすることもできます。フロントエンドエンジニアの方はぜひニフティクラウド mobile backend を使って便利なWebアプリケーションを開発してください!

f:id:mbaasblog:20180927104348p:plain