Parseでちゃんとアプリ
を作るコツ
∼サーバー運用をしないアプリ開発の時代へ∼
Indie Inc.
Co-Founder & CTO
Takuya Tejima
自己紹介
• Takuya Tejima (@tejitak)
• IBM -> LINE -> Indie Inc
※ DevMorningという朝活を毎週やってます
Parseとは
• https://parse.com/
• 2013年にFacebookが買収したMBaaS(Mobile Backend as a Service)
2015/12現在 IoTなどに力を入れている模様
(AppleTV / AppleWatch向けSDK公開)
ReactベースのDashboardに書き換えられた
日本だと、CyberAgent, mixi, Wantedly, Tokyo OtakuModeなどが大きなユーザー
Parseの特長
• バックエンド実装のサービス化
• Data Store
• インデックス自動生成&勝手にスケールしてくれる!!
• ユーザー管理 (Auth / Role)
• プラットフォーム対応
• SDK for Desktop + Web / Mobile / Embedded + IoT
• File / Code Hosting
• Mobile Push配信
• App Monitor / Analytics
Pricing
• https://parse.com/pricing
Data Store
30req/sec
Data/File 20GB / Transfer 2TB
までFree
Push
100万通知/月まで
Free
Analytics
Free
実際BaaSってどうなの?
• 複雑な処理やクラス構造に対応できるの?
• -> できる
• パフォーマンスは?
• -> 自前でチューニングした方が速いかもしれないが、Facebookが作ってるし大丈夫かと
• 学習コストは?
• -> 2, 3日ドキュメント読めば大体わかるかと
• 将来replaceできるの?
• -> Parse上で定義したAPIと同じものであれば容易に移行できるはず
個人的な結論
使うかどうかは結局費用対効果の問題。例えばサーバーの運用をす
るメンバーがいない場合は、積極的に使う価値がある
Parseで作ってみた
• https://hashdish.com
現在Beta版。ぜひご意見などお待ちしております。
ちゃんとアプリを開発するためのParseの機能紹介
• SDK
• Data Store
• Class定義
• GeoPoint
• File
• relationship (Pointer / Relation)
• 認証 / SNS連携
• Role / ACL
• API Console
• Cloud Code
SDK
• 豊富な種類のSDKが用意されている
• https://parse.com/docs
まずはREST APIのDocumentを読むことがオススメ(他のSDKはREST APIをWrapしている)
https://parse.com/docs/rest/guide
SDK
• オブジェクトを新規保存するコード例 (JS)
var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();
gameScore.set("score", 1337);
gameScore.set("playerName", "Sean Plott");
gameScore.save(null, {
success: function(gameScore) {
alert('New object created with objectId: ' + gameScore.id);
},
error: function(gameScore, error) {
}
});
• オブジェクトを読み出すコード例 (JS)
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.get("xWMyZ4YEGZ", {
success: function(gameScore) {
// The object was retrieved successfully.
},
error: function(object, error) {
}
});
https://parse.com/docs/js/guide
(JS SDKはbackbone.jsベースで作られている)
クラス定義
• Data Browserで直接データの管理ができる
• クラス定義
• データセットの雛型をクラスとして定義できる
• 自由にカラムを追加できる(後から柔軟にスキーマの変更が可能)
• カラム(クラスのフィールド)ごとに型の定義が可能
• 選択可能な型指定: Boolean, String, Number, Date, Object, Array,
GeoPoint, File, Pointer, Relation
• 型はJSON形式で“__type”プロパティとして格納される (e.g. __type: ’Pointer’)
• 全てREST APIで操作が可能
/1/classes/<className> POST Creating Objects
/1/classes/<className>/<objectId> GET Retrieving Objects
/1/classes/<className>/<objectId> PUT Updating Objects
/1/classes/<className> GET Queries
/1/classes/<className>/<objectId> DELETE Deleting Objects
REST API
File
• S3みたいなもの
• APIでPOST
• http://files.parsetfss.com/bc9f32df-2957-4bb1-93c9-
ec47d9870a05/tfss-db295fb2-8a8b-49f3-aad3-dd911142f64f-
hello.txt
• Objectの任意のpropertyに関連付け可能
• File自体のDELETEにはMaster Keyが必要
{
"name": "Andrew",
"picture": {
"name": "...profile.png",
"__type": "File"
}
}
GeoPoint
• GeoPointクラスを使用すると位置情報のクエリを簡単に実現で
きる
• __type=“GeoPoint”でlatitude /longitudeプロパティ
を持つ
• GeoQuery
• 与えた位置情報の近くを検索: $nearSphere
• 指定した2地点を橋とする四角形内で検索: $winthin.$box
Relationship (Pointer vs Relation)
• 参照・関係を表現する型としてPointerとRelationが使用できる
Pointer 参照オブジェクトを格納するもの。Pointerを保有クラスへの1回のクエリとして展開して含めることができる
Relation 関連を定義し、関連アイテムの追加・削除が可能。Relationを保有するクラスへの1回のクエリでは取得できない
• 関連ごとに幾つかのアプローチが可能
• Pointer (one-to-one、one-to-manyリレーション向け)
• Pointer Arrays (one-to-many、many-to-manyリレーション向け)
• Parse Relations (many-to-manyリレーション向け)
• Join Tables (many-to-manyリレーション向け)
• ArraysとRelationsの使い分けは?-> 一回で取得したい場合、そして数が少量(約100以下)ならArray
• Join Tabelsは?
• ケース1 参照関係を双方向から同レベルで解決したい時にArraysやRelationを双方向に持つより有
効 (e.g. この写真にいいねをした人のリストが欲しい / この人がいいねをした写真のリストが欲し
い) relationを双方に持たなくても逆のクエリは発行できるが、queryが非効率だったりする
• ケース2 “関係”そのものにメタデータが必要な時有効(e.g. 関係の作られた日時など)
認証・SNS連携
• 認証
• Pre-definedなUser / Sessionクラスが用意されている
• 各SDKに用意されているloginメソッドを使用するだけで、ユーザーデータ
の更新とセッションの管理をしてくれる
• SDKを使用しない場合は自前でsession tokenを保持する必要あり
(Webならcookieなどに保持してX-Parse-Session-Tokenをhttp
headerに付与)
• sessionのvalidationするには https://api.parse.com/1/
users/me or https://api.parse.com/1/sessions/me
• Facebook / Twitter OAuth認証はParseの設定画面でAppIDなどを
セットしておけばSDKによってコードレスで実現可能
Role / ACL
• UserにAssignできるRoleを定義できる
• 例: Admin roleの定義など
• 各Role / UserごとにACLを設定できる
• 例: Publicにはread only, adminと特定ユーザーだけwriteも許可
API Console
• Debug用に便利なAPI Consoleが提供されている
• Demo
Likeの実装例
• クラス構成のアプローチ
• 1 Pointer Arrayを使う
• 2 Relationを使う
• 3 Join Tableを使う
• HashDishでは将来の拡張性を考慮してActivityというクラスをJoin Tableとして使っている
• 適切なACLの設定
• ACLの付与はRow単位。Columnごとに設定できないので、一つのクラスに編集させ
たくないデータとユーザが変種可能なデータは基本的に混在してはいけない (->
後述のCloud Codeをすることで実装することは可能)
Cloud Code
• Trigger: コードをParseにhostして、データ変
更をhookすることができる
• beforeSave, afterSave,
beforeDelete, afterDelete
• 追加処理 (e.g. likeされたら別クラス
にlike countをincrement)
• validation (e.g. すでに同じユーザー
がlikeしているかどうかcheck)
• Function:
• JSのコードで独自のAPIを実装できる
• session tokenがvalidなリクエストの場合User情報を利用できる
• リクエストをまとめたい時に便利
• debugは少し大変
• debugger + node-inspectorでなんとかなる
• https://github.com/mariusciocan/parse-cloud-debugger
• JSのコードをホスティングして、API hookや独自のAPIを定義することができる強力な仕組み
Cloud Code Triggerの例
• likeした時にadmin roleとそのユーザー自身のみwrite可のACLを付与するhookを追加する例
var Activity = Parse.Object.extend("Activity");
var createMyACL = function(userId) {
var acl = {};
acl["*"] = {"read": true};
acl["role:admin"] = {"read": true, "write": true};
acl[userId] = {"read": true, "write": true};
return acl;
};
var assignACLTrigger = function(request, response) {
// allow master
if (request.master) {
return response.success();
}
// user must be authenticated
if (request.user) {
// Request to update existing row. Let it proceed.
// The PUT request will cause error by ACL if the user is invalid
if (!request.object.isNew()) {
return response.success();
}
// set ACL for POST request
request.object.set('ACL', createMyACL(request.user.id));
response.success();
} else {
return response.error("Not logged in.");
}
}
// modify POST request with ACL
Parse.Cloud.beforeSave(Activity, assignACLTrigger);
Parseを活用するためのコツ
• クラスの定義はPointer / Relation / JoinTableを場合に応じて利用する
• ACLの設定はきちんとする(デフォルトでpublic read/writeになってたら誰
でもデータ消せちゃうよ)
• Cloud Codeの活用
• 適切な追加処理の実装
• ACLの付与やvalidationなど各プラットフォームのクライアントでの冗
長な実装の防止。
• リクエストの効率化
• 完全にRESTfulだと初期ページに3 requestsくらい必要だったりする
-> cloud codeで一つにまとめる
他にも色々な機能がある
• サーバーテンプレートのホスティング (cloud codeでexpressが動くらしい)
• Jobs
• Schedule可能なbatch処理の実行
• Push
• ユーザーグループを作って配信するだけ
• schedulingもdashboardから可能
• localize
• 100万件/月 配信まで無料
• Analytics
Thank you

Parseでちゃんとアプリを作るコツ

  • 1.
  • 2.
    自己紹介 • Takuya Tejima(@tejitak) • IBM -> LINE -> Indie Inc ※ DevMorningという朝活を毎週やってます
  • 3.
    Parseとは • https://parse.com/ • 2013年にFacebookが買収したMBaaS(MobileBackend as a Service) 2015/12現在 IoTなどに力を入れている模様 (AppleTV / AppleWatch向けSDK公開) ReactベースのDashboardに書き換えられた 日本だと、CyberAgent, mixi, Wantedly, Tokyo OtakuModeなどが大きなユーザー
  • 4.
    Parseの特長 • バックエンド実装のサービス化 • DataStore • インデックス自動生成&勝手にスケールしてくれる!! • ユーザー管理 (Auth / Role) • プラットフォーム対応 • SDK for Desktop + Web / Mobile / Embedded + IoT • File / Code Hosting • Mobile Push配信 • App Monitor / Analytics
  • 5.
    Pricing • https://parse.com/pricing Data Store 30req/sec Data/File20GB / Transfer 2TB までFree Push 100万通知/月まで Free Analytics Free
  • 6.
    実際BaaSってどうなの? • 複雑な処理やクラス構造に対応できるの? • ->できる • パフォーマンスは? • -> 自前でチューニングした方が速いかもしれないが、Facebookが作ってるし大丈夫かと • 学習コストは? • -> 2, 3日ドキュメント読めば大体わかるかと • 将来replaceできるの? • -> Parse上で定義したAPIと同じものであれば容易に移行できるはず 個人的な結論 使うかどうかは結局費用対効果の問題。例えばサーバーの運用をす るメンバーがいない場合は、積極的に使う価値がある
  • 7.
  • 8.
    ちゃんとアプリを開発するためのParseの機能紹介 • SDK • DataStore • Class定義 • GeoPoint • File • relationship (Pointer / Relation) • 認証 / SNS連携 • Role / ACL • API Console • Cloud Code
  • 9.
    SDK • 豊富な種類のSDKが用意されている • https://parse.com/docs まずはRESTAPIのDocumentを読むことがオススメ(他のSDKはREST APIをWrapしている) https://parse.com/docs/rest/guide
  • 10.
    SDK • オブジェクトを新規保存するコード例 (JS) varGameScore = Parse.Object.extend("GameScore"); var gameScore = new GameScore(); gameScore.set("score", 1337); gameScore.set("playerName", "Sean Plott"); gameScore.save(null, { success: function(gameScore) { alert('New object created with objectId: ' + gameScore.id); }, error: function(gameScore, error) { } }); • オブジェクトを読み出すコード例 (JS) var GameScore = Parse.Object.extend("GameScore"); var query = new Parse.Query(GameScore); query.get("xWMyZ4YEGZ", { success: function(gameScore) { // The object was retrieved successfully. }, error: function(object, error) { } }); https://parse.com/docs/js/guide (JS SDKはbackbone.jsベースで作られている)
  • 11.
    クラス定義 • Data Browserで直接データの管理ができる •クラス定義 • データセットの雛型をクラスとして定義できる • 自由にカラムを追加できる(後から柔軟にスキーマの変更が可能) • カラム(クラスのフィールド)ごとに型の定義が可能 • 選択可能な型指定: Boolean, String, Number, Date, Object, Array, GeoPoint, File, Pointer, Relation • 型はJSON形式で“__type”プロパティとして格納される (e.g. __type: ’Pointer’)
  • 12.
    • 全てREST APIで操作が可能 /1/classes/<className>POST Creating Objects /1/classes/<className>/<objectId> GET Retrieving Objects /1/classes/<className>/<objectId> PUT Updating Objects /1/classes/<className> GET Queries /1/classes/<className>/<objectId> DELETE Deleting Objects REST API
  • 13.
    File • S3みたいなもの • APIでPOST •http://files.parsetfss.com/bc9f32df-2957-4bb1-93c9- ec47d9870a05/tfss-db295fb2-8a8b-49f3-aad3-dd911142f64f- hello.txt • Objectの任意のpropertyに関連付け可能 • File自体のDELETEにはMaster Keyが必要 { "name": "Andrew", "picture": { "name": "...profile.png", "__type": "File" } }
  • 14.
    GeoPoint • GeoPointクラスを使用すると位置情報のクエリを簡単に実現で きる • __type=“GeoPoint”でlatitude/longitudeプロパティ を持つ • GeoQuery • 与えた位置情報の近くを検索: $nearSphere • 指定した2地点を橋とする四角形内で検索: $winthin.$box
  • 15.
    Relationship (Pointer vsRelation) • 参照・関係を表現する型としてPointerとRelationが使用できる Pointer 参照オブジェクトを格納するもの。Pointerを保有クラスへの1回のクエリとして展開して含めることができる Relation 関連を定義し、関連アイテムの追加・削除が可能。Relationを保有するクラスへの1回のクエリでは取得できない • 関連ごとに幾つかのアプローチが可能 • Pointer (one-to-one、one-to-manyリレーション向け) • Pointer Arrays (one-to-many、many-to-manyリレーション向け) • Parse Relations (many-to-manyリレーション向け) • Join Tables (many-to-manyリレーション向け) • ArraysとRelationsの使い分けは?-> 一回で取得したい場合、そして数が少量(約100以下)ならArray • Join Tabelsは? • ケース1 参照関係を双方向から同レベルで解決したい時にArraysやRelationを双方向に持つより有 効 (e.g. この写真にいいねをした人のリストが欲しい / この人がいいねをした写真のリストが欲し い) relationを双方に持たなくても逆のクエリは発行できるが、queryが非効率だったりする • ケース2 “関係”そのものにメタデータが必要な時有効(e.g. 関係の作られた日時など)
  • 16.
    認証・SNS連携 • 認証 • Pre-definedなUser/ Sessionクラスが用意されている • 各SDKに用意されているloginメソッドを使用するだけで、ユーザーデータ の更新とセッションの管理をしてくれる • SDKを使用しない場合は自前でsession tokenを保持する必要あり (Webならcookieなどに保持してX-Parse-Session-Tokenをhttp headerに付与) • sessionのvalidationするには https://api.parse.com/1/ users/me or https://api.parse.com/1/sessions/me • Facebook / Twitter OAuth認証はParseの設定画面でAppIDなどを セットしておけばSDKによってコードレスで実現可能
  • 17.
    Role / ACL •UserにAssignできるRoleを定義できる • 例: Admin roleの定義など • 各Role / UserごとにACLを設定できる • 例: Publicにはread only, adminと特定ユーザーだけwriteも許可
  • 18.
    API Console • Debug用に便利なAPIConsoleが提供されている • Demo
  • 19.
    Likeの実装例 • クラス構成のアプローチ • 1Pointer Arrayを使う • 2 Relationを使う • 3 Join Tableを使う • HashDishでは将来の拡張性を考慮してActivityというクラスをJoin Tableとして使っている • 適切なACLの設定 • ACLの付与はRow単位。Columnごとに設定できないので、一つのクラスに編集させ たくないデータとユーザが変種可能なデータは基本的に混在してはいけない (-> 後述のCloud Codeをすることで実装することは可能)
  • 20.
    Cloud Code • Trigger:コードをParseにhostして、データ変 更をhookすることができる • beforeSave, afterSave, beforeDelete, afterDelete • 追加処理 (e.g. likeされたら別クラス にlike countをincrement) • validation (e.g. すでに同じユーザー がlikeしているかどうかcheck) • Function: • JSのコードで独自のAPIを実装できる • session tokenがvalidなリクエストの場合User情報を利用できる • リクエストをまとめたい時に便利 • debugは少し大変 • debugger + node-inspectorでなんとかなる • https://github.com/mariusciocan/parse-cloud-debugger • JSのコードをホスティングして、API hookや独自のAPIを定義することができる強力な仕組み
  • 21.
    Cloud Code Triggerの例 •likeした時にadmin roleとそのユーザー自身のみwrite可のACLを付与するhookを追加する例 var Activity = Parse.Object.extend("Activity"); var createMyACL = function(userId) { var acl = {}; acl["*"] = {"read": true}; acl["role:admin"] = {"read": true, "write": true}; acl[userId] = {"read": true, "write": true}; return acl; }; var assignACLTrigger = function(request, response) { // allow master if (request.master) { return response.success(); } // user must be authenticated if (request.user) { // Request to update existing row. Let it proceed. // The PUT request will cause error by ACL if the user is invalid if (!request.object.isNew()) { return response.success(); } // set ACL for POST request request.object.set('ACL', createMyACL(request.user.id)); response.success(); } else { return response.error("Not logged in."); } } // modify POST request with ACL Parse.Cloud.beforeSave(Activity, assignACLTrigger);
  • 22.
    Parseを活用するためのコツ • クラスの定義はPointer /Relation / JoinTableを場合に応じて利用する • ACLの設定はきちんとする(デフォルトでpublic read/writeになってたら誰 でもデータ消せちゃうよ) • Cloud Codeの活用 • 適切な追加処理の実装 • ACLの付与やvalidationなど各プラットフォームのクライアントでの冗 長な実装の防止。 • リクエストの効率化 • 完全にRESTfulだと初期ページに3 requestsくらい必要だったりする -> cloud codeで一つにまとめる
  • 23.
    他にも色々な機能がある • サーバーテンプレートのホスティング (cloudcodeでexpressが動くらしい) • Jobs • Schedule可能なbatch処理の実行 • Push • ユーザーグループを作って配信するだけ • schedulingもdashboardから可能 • localize • 100万件/月 配信まで無料 • Analytics
  • 24.