------------------------------------------------------------------------------------------
Introduction
Graph APIは、個々のオブジェクトやオブジェクト同士の繋がりのデータを取得するように設計されているだけでなく、複数のオブジェクトを同時に取得する機能も持っています。大量のデータに対して1度にアクセスしたかったり、複数個のオブジェクトを1度に変更したい場合は、個々にHTTPリクエストを送るよりも一括で処理する方が効率的です。それを可能にするためにGraph APIはバッチリクエストをサポートしていて、これにより、一度のHTTPリクエストで複数処理の指示を渡すことができます。以下のセクションで説明しますが、関連する処理同士の依存関係を記述することも可能です。Facebookは独立した処理を並列で処理し、依存し合う処理は順番に処理します。全ての処理が完了すると統合されたレスポンスが返され、HTTP接続が断たれます。
Making a simple batched request
バッチAPIでは、JSONの配列で表現した"HTTP リクエスト"を用います。つまり、それぞれのリクエストは以下の要素で成り立ちます。
- メソッド(HTTPメソッドのGET/PUT/POST/DELETE その他に該当)
- relative_url(graph.facebook.comに続く部分)
- オプションでヘッダ情報(HTTPヘッダに該当)
- オプションでボディ(POSTとPUT用)
そして、バッチAPIではJSONの配列で表現したHTTPレスポンスが返されます。要素は以下の通りです。
- ステータスコード
- オプションでヘッダ情報
- オプションでボディ(JSONエンコードされた文字列)
バッチリクエストを実行するには、個々の処理をJSON形式で記述し、https://graph.facebook.comにPOST送信します。以下の例は、ログイン中のユーザ自身のプロフィールと共に、友だち50人の情報を一回のリクエストで取得しています。
curl \
-F 'access_token=…' \
-F 'batch=[ \
{"method": "GET", "relative_url": "me"}, \
{"method": "GET", "relative_url": "me/friends?limit=50"} \
]'\
https://graph.facebook.com
これら両方の処理が完了すると、Facebookは個々のレスポンスをまとめて返します。それぞれのレスポンスにはステータスコード、ヘッダ情報、ボディが含まれます。これらは、Graph APIで個別にリクエストした場合と同じものです。bodyフィールドはエンコードされたJSONオブジェクトで、上記例の場合だと、以下のような形式になります。
[
{ "code": 200,
"headers":[
{ "name": "Content-Type",
"value": "text/javascript; charset=UTF-8" }
],
"body": "{\"id\":\"…\"}"},
{ "code": 200,
"headers":[
{ "name":"Content-Type",
"value":"text/javascript; charset=UTF-8"}
],
"body":"{\"data\": [{…}]}}
]
Batch requests containing multiple methods
通常ならば異なるHTTPメソッドを使い分けるような処理も1個のバッチリクエストに含めることが可能です。GETとDELETEはrelative_urlとmethodフィールドしか持たないのに対し、POSTとPUTはオプションでbodyフィールドを渡すことができます。bodyフィールドを渡す際には、URLクエリ文字列のように、HTTP POST bodyの文字列と同じ形式にしてください。以下は、ユーザのニュースフィードに新規投稿し、ニュースフィーロから最新のアイテムを取得しています。curl \
–F 'access_token=…' \
-F 'batch=[ \
{ "method": "POST", \
"relative_url": "me/feed", \
"body": "message=Test status update&link=https://developers.facebook.com/" \
}, \
{ "method":"GET", \
"relative_url":"me/feed?limit=1" \
} \
]'\
https://graph.facebook.com
この結果は以下のようになります。
[
{ "code": 200,
"headers": [
{ "name":"Content-Type",
"value":"text/javascript; charset=UTF-8"}
],
"body":"{\"id\":\"…\"}"
},
{ "code": 200,
"headers": [
{ "name":"Content-Type",
"value":"text/javascript; charset=UTF-8"
},
{ "name":"ETag",
"value": "…"
}
],
"body": "{\"data\": [{…}]}
}
]
Errors
リクエストした処理のうち1つがエラーとなることもあり得ます。適切なパーミッションを持っていない場合などです。そういった場合には、バッチAPIは通常のGraph APIと似たレスポンスを、バッチレスポンスの形式に則って返します。curl \
-F 'access_token=...'\
-F 'batch=[{ "method": "POST", \
"relative_url": "me/feed", \
"body": "message=Test update"}]\
https://graph.facebook.com
例えば、上記のアクセストークンがpublish_streamパーミッションを持っていなかったとしましょう。その場合のレスポンスは以下のようになります。
[
{ "code": 403,
"headers": [
{"name":"WWW-Authenticate", "value":"OAuth…"},
{"name":"Content-Type", "value":"text/javascript; charset=UTF-8"} ],
"body": "{\"error\":{\"type\":\"OAuthException\", … }}"
}
]
同じリクエストで指定した他の処理は通常通り完了し、ステータスコード200と共に返されます。
Using fql.query and fql.multiquery in the Batch API
Batch APIは旧REST APIメソッドをサポートしていませんが、fql.queryとfql.multiqueryをBatch APIリクエストに含めることは可能です。例えば、以下の例のようにFQLクエリを含めることができます。
curl \
-F 'access_token=…' \
-F 'batch=[{ "method": "POST", \
"relative_url": "method/fql.query?query=select+name+from+user+where+uid=4", \
}]
https://graph.facebook.com
Specifying dependencies between operations in the request
デフォルトでは、Batch APIのリクエストで渡される処理は独立したもので、サーバ側でどの順番で処理されても問題なく、1つの処理でエラーが起きたとしても他の処理には影響しません。しばしば、依存し合う処理をリクエストしたい場合があります。たとえば、一方の処理の結果を次の処理に渡したい場合です。Batch RequestはJSONPath(http://code.google.com/p/jsonpath/)の利用でこれをサポートしています。JSONPath形式での記述によってJSONオブジェクト内のデータを参照することが可能になります。実行済み処理(親)の結果を参照するには、実行済み処理を命名し、クエリ文字列内でそれを参照するかJSONPath形式でパラメータを生成します。クエリ文字列やパラメータを生成するときのJSONPath表記は、{result=(親処理名):(JSONPath表記)} となります。セキュリティのため、filterとscriptを用いたJSONPath生成は利用できません。たとえば、あなたの友だち5人の詳細を得るには、以下のようなバッチリクエストを送信します。
curl \
-F 'access_token=...' \
-F 'batch=[{ "method": "GET", \
"name" : "get-friends", \
"relative_url": "me/friends?limit=5", \
}, \
{ "method": "GET", \
"relative_url": "?ids={result=get-friends:$.data.*.id}" \
}]' \
https://graph.facebook.com/
上記の例では、1個目の処理はget-friendsと命名され、2個目の処理はJSONPath構文中で友だちIDを取得しています。JSONPath表記の $.data.*.id は、トップレベルの要素の全雇用そのIDを取得することを意味します。
上記の例ではJSONPathを用いて2個目の処理が1個目の処理を参照しているため、サーバは2個目の処理が1個目の処理に依存していることを察知します。そのため、依存されている側の処理が完了するまで、依存する側の処理は実行されません。親処理がエラーを返せば、依存する処理は実行されません。またデフォルトでは、処理が正しく完了した場合、親処理の結果はレスポンスには含まれません。
つまり、上記Batch APIリクエストのレスポンスは以下のようになります。
[
null,
{ "code": 200,
"headers":[
{ "name":"Content-Type",
"value":"text/javascript; charset=UTF-8"}
],
"body":"{\"data\": [{…}]}}
]
"omit_response_on_success":false を親処理に指定することによって、サーバに対して親処理の結果も返すように指示できます。例えば以下のように書きます。
curl \
-F 'access_token=...' \
-F 'batch=[{ "method": "GET", \
"name" : "get-friends", \
"relative_url": "me/friends?limit=5", \
"omit_response_on_success": false, \
}, \
{ "method": "GET", \
"relative_url": "?ids={result=get-friends:$.data.*.id}" \
}]' \
https://graph.facebook.com/
JSONPath利用によって実行済み処理を参照しています。たとえば以下の例では、1個目の処理で取得した友だち名を利用してステータス投稿します。
curl -F 'access_token=...' \
-F 'batch=[{ "method": "GET", \
"name" : "one-friend", \
"relative_url": "me/friends?limit=1", \
}, \
{ "method": "POST", \
"relative_url": "me/feed", \
"body": "message={result=one-friend:$.data.0.name} is my friend" \
}]' \
https://graph.facebook.com/
先述したように、JSONPath表記によってサーバは自動的に依存関係を検出しますが、場合によっては特に実行順序を指定したい場合があります。その場合には、depends_onアトリビュートを使います。
たとえば、以下のリクエストでは、2個目の処理が1個目に依存するというのが指定されています。
curl
-F 'access_token=...' \
-F 'batch=[\
{ "method": "POST", \
"name": "first", \
"relative_url": "me/feed", \
"body": "message=Test status update" \
}, \
{ "method":"GET", \
"depends_on": "first", \
"relative_url":"me/feed?limit=1" \
}\
]' \
https://graph.facebook.com
Batch calls with JSONP
Batch APIはGrpah APIと同様にJSONPをサポートしています。つまりJSONPのコールバック関数はパラメータの callback クエリ文字列で指定できます。Specifying different access tokens for different operations
紹介した全部の例ではトップレベルのパラメータで一個のアクセストークンを指定したのみでした。Batch APIは柔軟ですので、個々のリクエストでもクエリ文字列やパラメータを通じてアクセストークンを指定できます。その場合、トップレベルで指定したアクセストークンはフォールバック用に用いられます。
これはユーザ毎に異なるアクセストークンを使いたい場合や、一部でアプリのアクセストークンを使いたい場合に便利です。
個々のリクエストのいずれでもアクセストークンが指定されていない場合、トップレベルにアクセストークンを指定しなくてはなりません。
Uploading binary data
The following example shows how to upload 2 photos in a single batch call:
Batch APIリクエストのmultipart/mimeに指定することでバイナリデータをアップロードできます。これを実行するには、multipart/mimeタイプの添付として全バイナリデータを追加し、個々の処理がattached_filesプロパティを通じて参照できるようにします。attached_filesプロパティはカンマ区切りで添付ファイル名を指定することが可能です。
以下の例は、2個の画像ファイルを1回のバッチリクエストでアップロードしています。
curl
–F 'access_token=…' \
-F 'batch=[{"method":"POST", \
"relative_url":"me/photos", \
"body":"message=My cat photo" \
"attached_files":"file1" \
},
{"method":"POST", \
"relative_url":"me/photos", \
"body":"message=My dog photo" \
"attached_files":"file2" \
},
]'
-F 'file1=@cat.gif' \
-F 'file2=@dog.jpg' \
https://graph.facebook.com
Limits
一度に実行できる処理の上限は、現在50個です。