Rest経由のparseを使うBackbone.Viewを自作する
parse.comはiOS/android/Backbone.js等の各clientが準備されているが、
Restの口も準備されているので、実質、どの言語からも叩く事が出来る。
公式pageの内容をまとめて試してみて、
最後にBackboneのViewに組み込んでPluginにしてみた。
そこまでのメモ
メリデメ
先にメリデメまとめると、
- メリット
- とにかく気軽(Backend全く準備が要らない)
- 1ヶ月100万requestまでは無料
- デメリット
- 少し気になる程、遅い。(後述)
- Parse固有の事がある(relation等)ので、これで書いてしまうと、ベンダーロックされる
- queryがmongoDB丸だしなので、これも書いてしまうと、mongoDBから抜け出すのが大変
いずれにせよ、単純なテーブル構成でとりあえず作って見た、的なもの
※ハッカソンや個人制作アプリやモック制作等。
で良ければ、これで十分。
※勿論、parseをproductで使う予定があるのであれば、そのまま作って行けば何も問題は無い。プロダクト事例もいっぱいあるしね。
http header
ヘッダにApplicationIdとRestApiKeyが必要
- それぞれparse.com上の設定画面からコピペしておく
X-Parse-Application-Id: Your App Id X-Parse-REST-API-Key: Your REST API Key
※urlのhostにBasic認証のID/パスワード書く形でも上記のIDとKeyを書けるみたい。
URL + HTTPメソッド
endpointのapi.parse.comに対して、以下のURLを組み立てる
http://api.parse.com/<version>/classes/<className>/<objectId>
上記の
< >
=自分で記述するparamater- version
- 今とりあえず、
1
でいいみたい。
- 今とりあえず、
- className
- Parse側で保存したいリソース名。テーブル名。要するにmongoDBのコレクション名。
- objectId
- Parseで管理している識別子。要するに、mongoDBのid。ある特定のリソースを指定したい時に、記述する。(次のHTTPメソッドに詳しく書く)
- version
HTTP メソッド
- 新規作成:POST
- objectId付けない。
- 取得:GET
- 全件取得はobjectId付けない。
- 1件取得はobjectId付ける。
- 更新:PUT
- objectId付けて、何を更新するか指定が必要。
- 削除:DELETE
- objecjtId付けて、何を削除するか指定が必要。
- 新規作成:POST
URL+httpメソッドの例
例えば、tasksというクラスに対するCRUD操作は以下になる。
# Create POST http://api.parse.com/1/classes/tasks/ # Read(全件取得) GET http://api.parse.com/1/classes/tasks/ # Read(1件取得) GET http://api.parse.com/1/classes/tasks/abCDefGHij # Update PUT http://api.parse.com/1/classes/tasks/abCDefGHij # Delete DELETE http://api.parse.com/1/classes/tasks/abCDefGHij
curlで試す
curlで試してみる
新規作成
curl -X POST \ -H "X-Parse-Application-Id: YourApplicationId" \ -H "X-Parse-REST-API-Key: YourRestApiKey" \ -H "Content-Type: application/json" \ -d '{"score":1337,"playerName":"Sean Plott","cheatMode":false}' \ https://api.parse.com/1/classes/GameScore
- もし、存在しないclassName指定すると、新規にclass自体を作ってくれる
- 但し、その時、結構、遅い(今やったら8secかかった)
- 既にあるclassNameであれば、1,2sec程(それでも遅いですね)
取得
- 以下で全件取得してみる
curl -X GET \ -H "X-Parse-Application-Id: YourApplicationId" \ -H "X-Parse-REST-API-Key: YourRestApiKey" \ https://api.parse.com/1/classes/GameScore/
- 例えば、2件同じデータを入れてみたときの出力結果
{"results":[ {"score":1337, "playerName":"Sean Plott", "cheatMode":false, "createdAt":"2013-12-13T13:24:07.037Z", "updatedAt":"2013-12-13T13:24:07.037Z", "objectId":"ilCXeuD0Iv"}, {"score":1337, "playerName":"Sean Plott", "cheatMode":false, "createdAt":"2013-12-13T13:24:32.211Z", "updatedAt":"2013-12-13T13:24:32.211Z", "objectId":"io5sO9G2gQ"}]}
- 1件取得したければ、上記のobjectIdをurlの最後のpathに入れる
更新
- 上記の一番上のデータを更新してみる
curl -X PUT \ -H "X-Parse-Application-Id: YourApplicationId" \ -H "X-Parse-REST-API-Key: YourRestApiKey" \ -H "Content-Type: application/json" \ -d '{"score":73453}' \ https://api.parse.com/1/classes/GameScore/ilCXeuD0Iv
- うーん時間かかる(2sec程)
- 更新をした後で、改めて、GETで、取得してみると、更新されてる。
- なんか、CRUDで更新が一番、時間かかるっぽい
- 何度も更新していくと、落ち着いてくるので、mongodbのinplace updateはみ出て、padding factor調整してるっぽい動き
BackboneでRestのparseを使う
ここからが、本題。
やりたい事
Parse.comでBackbone.js用のClientがあるのに、これがイマイチ。現実的に使えない。
やりたいのは、単純にBackbone.syncのバックエンドとしてparse使えればいいだけなのに。
parse付属のBackboneクライアントの何がイマイチなのか?
古いBackboneをforkして、かなり独自に実装してしまってる
- Backbone.Objectって?
- 中見るとBackbone.Modelから大分違うソースになってる
- validation周りの動きが変。
- Backbone.Syncすら無い。
- イベントsyncとかrequestとか動きが変(無い)
結論、これに別のプラグインとか突っ込んで行くと色々問題があって、結局使えない。
多分、あえて独自実装にして、ベンダーロックインさせたいんだろうけど、
出来れば、Backbone本体+αでどうにかしたい。
そうしたら、他のpluginも使えるし。
Backbone.Model内でどうにかする
という事で書いてみた
var Task = Backbone.Model.extend({ urlRoot: "https://api.parse.com/1/classes/tasks" }); var myTask = new Task(); myTask.set({"name": "jikken"}); myTask.save({}, { headers:{ 'X-Parse-Application-Id': ‘YourAppId’, 'X-Parse-REST-API-Key': ‘YourRestAPIKey’ }});
parseのRESTの使い方に沿って、単にヘッダー追加しただけ。
なお、ssl入れないと通らないので注意。
plugin化
毎回、こんなView書いて行ったら大変なので、
これをpluginとして作って見た。
https://github.com/lxyuma/backbone-parse-sync
Backbone.Viewを拡張してる。
使い方
githubに書いた通りだけど、
- parseHeadersにid/keyをセット
- Model/CollectionのuseParse:trueにすればいいだけ。
<script src="dist/backbone-parse-sync.min.js"></script> <script> // settings window.parseHeaders = { ApplicationId: "*****************************", RESTAPIKey: "*****************************" }; // Model TestModel = Backbone.Model.extend({ useParse: true, urlRoot: "/blogs" // this means using parse 'blogs' object }); testObject = new TestModel(); testObject.set({'name': 'test'}); testObject.save(); </script>
これで、各CRUD処理書くと、parseに対してRESTしてCRUDする。
本体ソース
短いので、貼付けるが、前に書いたソースと大体同じ様な感じで、
- ヘッダー追加してsyncして
- parseする時に、json調整してる
sync: function(){ if (this.useParse === true) { _.extend(_.last(arguments), { url: "https://api.parse.com/" + this.parseVersion + "/classes/" + _.result(this, "url"), headers: { 'X-Parse-Application-Id': window.parseHeaders.ApplicationId, 'X-Parse-REST-API-Key' : window.parseHeaders.RESTAPIKey} }); } return Backbone.sync.apply(this, arguments); }, parse: function(resp, options) { if (this.useParse === true && _.has(resp, "results")){ return resp.results; } else { return resp; } }
おしまい
まあ、クライアント側にkey/id貼付けてるのも気になるので、
お遊びや検証/学習やモック作成やハッカソン等で
上記plugin等使えればいいかと。