Facebook開発者向けドキュメントの日本語訳とTips

http://developers.facebook.com/docs/ に記載されているdocumentationの和訳と、調べていて分かったノウハウを紹介します。
Life is tough, so are we.
ドキュメント全体の目次はこちら
Facebook関連情報はFacebookページで共有しています。

PHP SDKに足されたappsecret_proofというパラメータ

CPANに上げたFacebook::OpenGraphの次の実装を進める上で、PHP SDKの実装を参考にしようと思い、中身を見ていて不思議なパラメータを見つけました。5/15のマージでmasterに反映されたもので、HTTPリクエスト送信時、アプリの秘密鍵とアクセストークンを基に生成した文字列をappsecret_proofというクエリパラメータで送るというものです。おまけに「全API呼び出しで必須」というコメントも書かれているのが不気味です。

詳細については「続・PHP SDKに足されたappsecret_proofというパラメータ」という補足エントリを参照してください。

ae2f40afd1cf1f539efbaa7045fba84f


API利用時の流れ

普段はPerlで開発しているため、PHP SDKを扱うのは初めて。まずはリクエストまでの流れを把握するところから始めました。PHPを書くことが無いので、怪しいところがあるかもしれません。
/* 初期化 */
$facebook = new Facebook(array( 'appId' => 'YOUR_APP_ID', 'secret' => 'YOUR_APP_SECRET', ));


/* go.hagiwara オブジェクトを取得 */
$facebook->api('/go.hagiwara', 'GET');

api()は、まず旧REST APIを使うか新Graph APIを使うかを引数を元に判別し、よしなにしてくれます。

  /**
   * Make an API call.
   *
   * @return mixed The decoded response
   */
  public function api(/* polymorphic */) {
    $args = func_get_args();
    if (is_array($args[0])) {
      return $this->_restserver($args[0]);
    } else {
      return call_user_func_array(array($this, '_graph'), $args);
    } 
  }

_graph()が呼ばれ、その中で主に以下の内容を扱います。
  1. HTTPリクエストメソッドの指定
  2. ビデオ投稿か否かを判定してリクエスト先のドメインを指定
  3. _oauthRequest()を実行してHTTPリクエストを送る
  4. 返されるJSONをデコード
  5. エラーであれば例外を投げる
  /**   
   * Invoke the Graph API.
   *
   * @param string $path The path (required)
   * @param string $method The http method (default 'GET')
   * @param array $params The query/post data
   *
   * @return mixed The decoded response object
   * @throws FacebookApiException
   */
  protected function _graph($path, $method = 'GET', $params = array()) {
    if (is_array($method) && empty($params)) {
      $params = $method;
      $method = 'GET';
    } 
    $params['method'] = $method; // method override as we always do a POST
    
    if ($this->isVideoPost($path, $method)) {
      $domainKey = 'graph_video';
    } else {
      $domainKey = 'graph';
    }

    $result = json_decode($this->_oauthRequest(
      $this->getUrl($domainKey, $path),
      $params
    ), true);

    // results are returned, errors are thrown
    if (is_array($result) && isset($result['error'])) {
      $this->throwAPIException($result);
      // @codeCoverageIgnoreStart
    }
    // @codeCoverageIgnoreEnd

    return $result;
  }

送るのは全てPOSTリクエスト

ここで一個注目したのは、リクエスト送信時には全てHTTPリクエストメソッドはPOSTに指定される(method override as we always do a POST)ということです。その代わり、GET, DELETE, POSTなど開発者が指定したリクエストメソッドはmethodというパラメータに指定されて残ります。最終的には以下のようになります。
curl -X POST \
       -F 'method=DELETE' \
       -F 'access_token=XXXXXX' \
       https://graph.facebook.com/OBJECT_ID_TO_DELETE

POSTメソッドとmethodパラメータの併用については、以下の通りGraph APIドキュメントの日本語訳でさらっと紹介されています。
オブジェクトのURLに対してHTTP DELETEリクエストを送信すると、グラフ上のオブジェクトを削除できます。
DELETE https://graph.facebook.com/ID?access_token=... HTTP/1.1
全HTTPメソッドをサポートしていないクライアント(JavaScriptクライアントなど)をサポートするには、代わりに、オブジェクトのURLに対してmethod=deleteというパラメータを追加してPOSTリクエストを送ります。
この説明だと、一部リクエストメソッドが利用できない場合の代替手段として、POSTメソッドとmethodパラメータの併用ができるというように読み取れます。そのため、公式のPHP SDKの実装が、全てのリクエストに関してこの手段を用いているのが意外でした。
FQLのマルチクエリはGETリクエストで実装するようドキュメントに書かれているため、クエリストリングが長くなりがちです。その長さの上限について調べようとしていたのが今回PHP SDKのコードを読むきっかけだったため、全てPOSTメソッドを利用してパラメータをContent-Bodyに詰め込んでいると分かったところで、当初の目的は達成できました。
が、興味本位でリクエストを投げる部分の実装まで見ていて見つけたのが、appsecret_proofパラメータです。

appsecret_proofパラメータ


  protected function _oauthRequest($url, $params) {
    if (!isset($params['access_token'])) {
      $params['access_token'] = $this->getAccessToken();
    }

    if (isset($params['access_token'])) {
      $params['appsecret_proof'] = $this->getAppSecretProof($params['access_token']);
    }

    // json_encode all params values that are not strings
    foreach ($params as $key => $value) {
      if (!is_string($value)) {
        $params[$key] = json_encode($value);
      }
    }

    return $this->makeRequest($url, $params);
  }
この中でgetAppSecretProof()にアクセストークンを渡し、appsecret_proofに指定する文字列を生成しています。
  /**
   * Generate a proof of App Secret
   * This is required for all API calls originating from a server
   * It is a sha256 hash of the access_token made using the app secret
   *
   * @param string $access_token The access_token to be hashed (required)
   *
   * @return string The sha256 hash of the access_token
   */
  protected function getAppSecretProof($access_token) {
    return hash_hmac('sha256', $access_token, $this->getAppSecret());
  }
ここで怖いのは、以下のコメントです。
This is required for all API calls originating from a server
It is a sha256 hash of the access_token made using the app secret
これはサーバからの全API呼び出しで必須となるものです。
アプリの秘密鍵とアクセストークンから生成するSHA256ハッシュ値です。
ただし、新しくアプリを作成し、テストユーザを生成して試してみましたが、適当な文字列を入れてみても何も問題は起きませんでした。appsecret_proofが渡された場合のバリデーションなどはまだ実装されていないのでしょうか。

>curl -X POST \
> -F 'access_token=テストユーザのアクセストークン' \
> -F 'method=GET' \
> -F 'appsecret_proof=qwrty' \
> https://graph.facebook.com/me

{"id":"100005943794526","name":"Ruth Ameidcgidebf Panditstein","first_name":"Ruth","middle_name":"Ameidcgidebf","last_name":"Panditstein","link":"http:\/\/www.facebook.com\/profile.php?id=100005943794526","gender":"female","timezone":0,"locale":"en_US","updated_time":"2013-05-24T11:25:55+0000"}
ただし、これに絡むエラーが返されているというケースもあるようで、今後が気になります。
Fatal error: Uncaught GraphMethodException: API calls from the server require an appsecret_proof argument thrown in .../.../lib/base_facebook.php on line 1238

規約的にFacebookページ名変更が厳しいとき

こんばんは。「FB開発者向けドキュメントの和訳とTips」管理人のOklahomerです。こんな書き出し方できるのも、Facebookページ名を「Oklahomer」から「FB開発者向けドキュメントの和訳とTips」に変えてもらったおかげです。

本来、個人の名前(ニックネーム)で作成したページをブランド名などに変更するのは規約的に厳しいのですが、何度かFacebook側担当者の方とメールのやりとりをして変えてもらうことができました。ここでは、Facebookページ名の変更申請手順と、その後のやりとりについて紹介します。

申請

ページ名変更についての大まかな流れは「200いいね!以上でもFacebookページ名は変更できる!? 変更申請方法」で紹介されている通りです。ただし、今では「ローカルビジネス」「企業・団体」カテゴリでない場合にも申請できるようです。私の場合、今年の2月頃に思い立って変更しようとした時点では、申請フォームへの導線が表示されていなかったものの、5月あたりに再度チェックしたら申請できるようになっていました。申請が完了すると自分のアカウントにメールが届き、審査に最大3日かかる旨が知らされます。

却下されたとき

ガイドラインの基準を満たさない場合、3日以内に却下メールが届きます。私の場合は、Oklahomerという個人名(ニックネーム)から変更することがファンを混乱させる、という理由での却下でした。詳細についてはガイドラインページで紹介されています。
そこで、もう一回送ってみたら審査の甘い人が対応してくれるんじゃ。。。と思ってもう1度申請したものの、2度目も同じ人から却下メールが届きました。窓口が一個では何度繰り返しても同じだという訳で、今度はメールで直接返信することにしました。そのとき送った内容は以下の通りです。
Hi 〇〇,

Thanks for your immediate reply.
早速の返信ありがとうございます。

I've read and understood the guidelines well.
I also understand avoiding fans' confusion is very important, but I still
don't understand why you stick with those guidelines like those are actual
rules.
If I may say, Rules are some things that you can not compromise, but
guidelines are things that indicate and help determine the course of action.
And when compromising guidelines helps to achieve the goal, avoiding fans'
confusion, I believe you should compromise a bit.
私はガイドラインを読み、よく理解しました。
ファンの混乱を避けることが重要だということも理解していますが、
なぜ、ガイドラインが実際のルールであるかのようにこだわるのか、理解に苦しみます。
言わせて頂くと、ルールは妥協の余地のないものですが、ガイドラインは行動の指針を示し、行動を決定する助けになるものです。
ガイドラインを多少曲げることが、ファンの混乱を避けるという目的達成に繋がるのならば、例外を認めるべきだと思います。


Once you see my page, you will find my page is all about Facebook
documentation, know-how and some tips for better Facebook app development. For the last 2 years, since I started this page, this page kept focusing on
this area. The page's About and Description sections are set to
"Facebook技術者向けドキュメントの和訳/Tipsや、Facebook絡みのニュースを紹介しています。http://facebook-docs.oklahome.net/" and "Support making the world more open and connected." And it even says this is a community page about Facebook.
With that said, I believe, changing page title from "Oklahomer" to "FB開発者向けドキュメントの和訳とTips" is reasonable and it's more confusing and irresponsible to leave this name as it is.
私のページを見て頂けば、このページが、Facebook開発ドキュメント、ノウハウ、より良いFacebookアプリを造る為のコツに関するものだと分かるはずです。
ページを開設して以来2年間、ずっとこの分野にフォーカスを当ててきました。
また、ページのAboutセクションとDescriptionセクションはそれぞれ、「Facebook技術者向けドキュメントの和訳/Tipsや、Facebook絡みのニュースを紹介しています。 http://facebook-docs.oklahome.net/」と「Support making the world more open and connected.」に設定されていますし、Facebookのコミュニティページとも設定されています。
これらを鑑みれば、「Oklahomer」を「FB開発者向けドキュメントの和訳とTips」という名前に変えるのは理にかなっていて、むしろこのページ名のままにする方が無責任で混乱を招くと思います。


I trust you make a reasonable decision.
Thank you in advance.

Go Hagiwara
このメールを送って30分経たずして変更完了というメールが送られ、ページを開いてみると確かに変更されていました。

ce24bfaac73e4d7ae527d2e630172087

本文中でページ名の変更は一度きりだと念を押されるので、申請出すときは間違いが無いよう気をつけましょう。もう変えられないと言われてしまうと、ついつい「FB開発ドキュメントの〜〜」って名前にしといた方が良かったんじゃないかとか思ってしまいます。「FB開発者向け〜〜」って長ったらしいし。。

まとめ

最初に適当なページ名を付けてしまい、活動を続けるうちに変更したくなって来たけど、ファン数200名以上だしガイドラインに引っかかるから申請できない、という方もいるかと思います。Facebook側の担当者だって、他の仕事もあるし一個一個の申請を詳細にチェックしていられないというわけで、ある程度は機械的にガイドラインと照らし合わせて却下してくるかもしれません。ただし、ガイドラインに多少引っかかろうとも、名前を変えた方が混乱を避けられるということを説明できれば、ちゃんと見て対応してくれるという印象でした。
ダメ元で何でもかんでも申請しようとは言いませんが、「ガイドライン的にアウトなんだけど、ページ名変えた方が絶対にファンにとっても分かり易いんだよなぁ」と思うだけの根拠があれば、申請してみると良いかもしれません。

URLもfacebook.com/Oklahomer から facebook.com/oklahomer.docs に変えたので、今度は新規にOklahomerというページを新設しました。あまり一個のトピックに絞ったブログ記事ばかり書いていると窮屈なときがあるので、新設ページは自由に個人目的で使おうかと思います。

2013/07/10 の仕様変更

4月の終わりになってFacebook Platformから通知が来ている通り、7/10に予定されている仕様変更への対応が求められています。2月の移行時の騒動と比べ、2ヶ月以上前から通知を送ってくるとは気が早い気がしますが、4月からリリースサイクルが変わったせいかもしれません。


6d5724bba743c83bca57a6250272727a


7/10に強制移行となる新仕様と変更は以下の通りです。この内容はアプリの設定画面(Settings > Advanced > Migrations)にある「July 2013 Breaking Changes」を有効にすることで早めに移行することも可能です。
  1. APIでコメントの返信機能が使えるようになる。(「Graph APIで新コメント欄の返信機能を扱う」で紹介したものです。)
  2. Like Box, Like Buttonを含むソーシャルプラグインで、hrefパラメータに該当webページの絶対URLを指定しなくてはならない。追記:hrefを指定する場合のみ。JS SDKなどで補完させる場合は含まれません。
  3. FQLのstreamテーブルが、無効なfilter_keyを指定した場合にエラーを返すようになる。有効な値を知るには、stream_filterテーブルを用いることができます。
  4. publish_checkinsパーミッションの無効化。位置情報を紐づけて投稿できるため、Checkinオブジェクトの投稿はできなくなります。これは、Open Graphアクション投稿と、通常のウォール投稿などの両方に適用されます。投稿系パーミッションの統合についての最近の流れについては「認可ダイアログとパーミッションの仕様変更」を参照してください。
  5. FQLのcheckinテーブルにあるpage_idカラムが、target_idという名前に変わります。(「ドキュメントの歩き方:FQL編」で各テーブルのIDの見分け方を紹介しましたが、その法則に従って分かり易くする狙いのようです。)
  6. FQLとGraph API双方のgroupオブジェクトが、versionフィールドを返さなくなります。2010年10月からグループの仕様が代わり、その新旧の区別のためにversionが返されていました。旧グループに関してはアーカイブ化、もしくは新グループへの移行が完了したため、versionが不要になったのがversion無効化の理由です。
  7. FQLのphotos, photo_srcテーブルは、アップロードされたオリジナル画像より大きなサイズの画像を返さなくなります。
  8. 同一Open Graphオブジェクトに対する複数のcreateアクション投稿ができなくなります。
  9. FQLのstream.commentsが廃止されます。comment_infoフィールドで取得できるJSON文字列からcan_comment(コメント可否。旧can_postに相当), comment_count(コメント数。旧countに相当)を見るようにしてください。
  10. FQLのcommentテーブルのxid, reply_xid, username, commentsカラムが廃止されます。これらは旧仕様のコメントプラグインの為に残されていましたが、今後はFacebook上でも外部でも同じものとしてコメント欄を扱うようになるため、「Graph APIで新コメント欄の返信機能を扱う」で紹介した方法を用いて返信を取得できるようになります。
  11. Graph APIのcommentsコネクションからcountが無くなります。これは元々ドキュメントに記載されていなかったもので、今後、count情報が取得したい場合は、/OBJEC_ID/comments?summary=trueを利用することになります。その際、これまでと違ってtotal_countというキーで返されるようになります。
以下の内容も7/10に有効になりますが、アプリの設定で早期に移行することはできません。
  1. Mobile App Install Adsで指定するapp_platform_typeパラメータがmobile_storeという名前に変わり、利用できる値はitunes, itunes_ipad, goole_playの3種になります。
  2. 広告のコンバージョン測定に用いるtracking_pixel_idが無効になり、新しいtracking_specsを使うことになります。
  3. ターゲティングで用いるexcluded_user_adclustersパラメータがexcluded_custom_audiencesに変わります。また、エンドポイントも変更され、https://graph.facebook.com/(act_adaccountid)/customaudiencesになります。
  4. FQLのlink_statテーブルへのアクセスにアプリのアクセストークンが要求されるようになります。
  5. Place, Page以外に対するGraph API検索でアプリのアクセストークンが要求されるようになります。
  6. フィットネス、本、映画、テレビ番組に対するOpen Graphアクションを独自に定義している場合、ビルトインアクションを利用するようにしなくてはなりません。
  7. Insights APIからpage_friends_of_fansが無くなります。
  8. Requestダイアログを利用する際、送信相手の選択画面で「全員を選択」したり自動でフィルインしておくことが、プライバシー規約に反するようになります。

詳細についてはDeveloper Roadmapを参照してください。

ドキュメントの歩き方:FQL編

去年12月以来、FQLのドキュメントはFacebook Platformのソースコードから生成されるようになりました。これにより、従来よりも正確でなおかつ最新の状態が保たれると発表されていますが、それでもドキュメントだけを頼りに開発を進めるのは辛いものです。

ここでは、私がFQLを扱う際の手順と注意している点について、ドキュメントを確かめるところからバグ報告を行うところまで紹介します。

  1. 本家ドキュメントを見る
    • 2種類のID
      • Open Graph上のユニークID
      • テーブル内でのユニークID
    • プロフィール
      • プロフィールID
  2. Graph API Explorerを使う
    • アクセストークン
    • 期待する結果が得られないとき
  3. バグ報告する
    • 報告する
      • APIの不具合を報告する
      • ドキュメントの誤りを報告する
  4. まとめ

1.本家ドキュメントを見る

fql

私自身もFQLドキュメントの和訳を公開していますが、常に更新され続ける情報には追いついていません。和訳を書いたころは、本家ドキュメント自体が古い仕様に基づいていたりもしました。今では本家ドキュメントが最新の状態に保たれているのですから、あくまで和訳はキッカケ程度にして、詳細については本家を参照するのが一番です。本人が言うんですから間違いありません。
ドキュメントを読む際には、いくつか気をつけている点があります。

2種類のID

Open Graph上のユニークID
2e4b0f4ab7a2d9c9ba0ae204e356f146

そもそもOpen Graphが何かというと、Facebookが持つソーシャルグラフをサードパーティの開発者向けに拡張したものです。そこでは、人間、画像、動画、ページ、アルバムなど、ソーシャルグラフを構成する全てのオブジェクトに固有のIDが割り振られています。ここでは他方との区別の為、Open Graph IDと呼ぶことにします。このIDはOpen Graph上で固有なため、 https://graph.facebook.com/ID へアクセスすることで、そのオブジェクトに関する情報を取得することができます。
テーブル内でのユニークID
c64ec031248e7aa081e9312532d846a9

userテーブルにはuid(user id)というカラムが存在します。これはOpen Graph IDなので、先述の通りOpen Graph上で固有のものです。https://graph.facebook.com/UID でユーザ情報を得ることができます。また、albumやphotoテーブルには、aid(album id)やpid(photo id)といったカラムが存在します。user.uidの流れで、これらもOpen Graph IDであるように見えます。事実、user.uidの説明は"The user ID"、album.aidの説明は"The album ID"と書かれているだけなので、扱いが違うようには見えません。
ところが実際には、album.aidやphoto.pidはテーブル内で固有なだけで、Open Graph上で割り振られたユニークIDではありません。そのため、ここで得られたaidを基に https://graph.facebook.com/AID にアクセスしても望む結果は得られません。こういったテーブルには大体、object_idといったカラムが存在し、それらがOpen Graph IDとなっています。
たとえばphotoテーブルの場合、aid, album_object_id, pid, object_idといったカラムが存在します。aidはalbumテーブルのUNIQUE KEYで、albumテーブルに対するクエリ実行で用いることができます。album_object_idは画像が属するアルバムオブジェクトのOpen Graph IDなので、https://graph.facebook.com/ALBUM_OBJECT_IDでアルバムにアクセスできます。同様に、pidはphotoテーブル中のUNIQUE KEYで、object_idはOpen Graph IDです。

プロフィール

プロフィールアイコンやプロフィールページと言われれば、普通はユーザに関係するものを想像すると思いますが、Facebook上では、Facebookページ、イベント、グループ、アプリにも個別のページが与えられます。それらのページではプロフィール画像を設定することもできますし、ウォール投稿したり画像や動画を投稿することもできます。そのため、それらもまとめてprofile(プロフィール)と呼ばれています。ドキュメント中でprofileという語が出てきた場合には、ユーザオブジェクトだけでなく、これらのOpen Graphオブジェクトも対象となることに気をつけてください。
プロフィールID
画像、動画、アルバムなどは何かしらのプロフィールに属します。ユーザが投稿した画像であればユーザプロフィールに属しますし、Facebookページが投稿した画像であればFacebookページプロフィールに属します。属するプロフィールのIDを返すカラムの名前が、テーブルによって違いがあるので注意してください。album.owner, comment.fromid, event.creator, event_member.uid, group.creator, status.uid, stream.source_id, stream_tag.actor_id, page_milestone.owner_idなどです。いずれも該当オブジェクトが紐づくプロフィールIDを返すカラムですが、ownerやuidなど呼び名が統一されていません。
ポイントとしては、uid(user id)というカラム名の場合はユーザのOpen Graph IDを指しているので、ユーザ以外のプロフィール(イベントやグループ)に属することはありません。逆に、ownerやowner_idという名称の場合は、ユーザ以外のプロフィールにも属しうるといえます。また、group.creatorやevent.creatorの場合は、あくまで作成したプロフィールのIDであって、管理者とは限らないことが分かります。(owner,uid,creatorを使い分けるのは分かりますが、ownerとowner_idはどちらかに統一して欲しい。。。)

2.Graph API Explorerを使う

explorer2
ドキュメントを読んで仕様を理解したら、まずはGraph API Explorerで試してみるのが一番です。この開発ツールでは、実際にAPIを利用して返される値を確かめることができます。

アクセストークン

graph_api_explorer
キャプチャ右上の赤枠部分のセレクトボックスでは、Graph API Explorerというアプリと、自分が開発者として関わっているアプリを選択することができます。ここでアプリを選択し、「Get Access Token」をクリックしてアクセストークンを生成し、そのアクセストークンを用いてFQLクエリを発行することになります。
このとき、いきなり自分のアプリを選択することはせず、まずはGraph API Explorerを選択してアクセストークンを生成するようにしています。APIの仕様は常に変更の対象で、変更の際には告知から90日間の移行期間が設けられています。この移行期間中は、アプリの設定画面で移行設定を行うことが可能です。そのため、同じクエリを発行していても、アプリごとの設定によって返る値が変わり得ます。こうなってくるとややこしいので、まずはGraph API Explorerのアクセストークンで最新の仕様に従ってクエリを実行し、そのあとに自分のアプリを選択し、そのアクセストークンを生成するようにしています。ステップが増えて面倒な気もしますが、期待通りの結果が得られない場合に、アプリの問題なのかFacebook側の問題なのかを切り分けるのが楽になります。

期待する結果が得られないとき


f1cd81cbe5c99cc28944abc5e757d2a4

このキャプチャは4/9に遭遇した不具合で、content_ageを含むクエリでエラーが返されるというものです。ドキュメントに従っているものの、どうしてもエラーが返されてしまいます。content_ageを除いて実行すると仕様に従った値が返されました。こうした場合にはバグ報告します。

3.バグ報告する

FQLのドキュメントを見つついろいろなクエリを試していると、ちょこちょこ不具合を見つけることがあります。直近1ヶ月の間に見つけて報告したFQL関連のものは以下の6件です。
  1. FQL place.search_type returns empty string
  2. FQL place.content_age column returns error
  3. FQL page table's budget_recs is returning error
  4. description for content and content_html column is different from its implementation and is misleading
  5. Sample query uses a column that does not exist
  6. FQL link table's comment_info.comment_order is unclear
1~3と5はFQLの不具合で、これらはアサインされ、ものによっては既にFIXEDになっています。
4,6はドキュメントの不備を報告したものです。完全に不具合という場合でないと修正対象とならないらしく、「型がENUMとなっているけど、どういう値が返りうるのか明記されてないよ(他のドキュメントページでは通常、明記されています)」とか「contentとcontent_htmlのカラムの説明が間違ってて誤解を招くよ」という報告をした結果、「Thank you」というコメントでCloseされています。
いきなりバグ報告だと敷居が高い、不具合なのか自信が無いという場合には、まずFacebook API Developers JAPANというグループに投稿してみるのが良いかもしれません。

報告する

APIの不具合を報告する
まずBugsに行きます。ここには開発者から報告されたバグが一覧で表示されていて、タグや検索によって絞り込むことができます。ここにはバグ報告フォームへのリンクがありません。検索バーに適当な文字列を入れて、出てくる候補の一番下にあるCreate a new bug reportをクリックすれば遷移します。
もしくは直接File a Bug Reportへ行って登録できます。
989bd7cc22bc140f0fa3ea566d273de9
概要
まずは、タイトル、概要、どの分野の不具合かを示すタグ、非公開(confidential)にするかを入力します。
アプリ情報
どのアプリでそれを再現しうるのかAppsに入力します。自分の関係しているアプリ名を入れると補完されますが、Graph API Explorer上で試していて、なおかつGraph API Explorerのアクセストークンを使って再現していた場合、何を入れるか迷ってしまいます。そんなときは、とりあえず何かしら自分のアプリを入れておくという方法もあります。
Related IDsには、関連するOpen GraphオブジェクトのIDを入力します。クエリ中で特定のオブジェクトを指定して再現するのであれば、それを入れます。
Access Tokensには、不具合を再現できるアクセストークンを入れます。Graph API Explorerで試していたなら、Explorerページ上に表示されているものを入れれば大丈夫でしょう。
再現方法
Steps to Reproduceには再現方法を登録します。以下のように書いておけば伝わります。
1. Visit Graph API Explorer.
2. Type in a query like "SELECT ......"
3. Submit
Expected Behaviorには期待する結果、Actual Behaviorには実際の結果を入力します。Actual Behaviorは返されたエラーを貼付けておけば大丈夫でしょう。見られたくない情報まで含まないように気をつけてください。
必要であれば、Attachmentsでキャプチャを添付します。
以上のステップが終わったらCreateで登録します。これで自分が登録したバグ一覧に表示され、ステータスの変化が分かるようになります。
ドキュメントの誤りを報告する
0cb8ddb7d041d7420e3802fe11cc128e

ドキュメントページ右下の「Report Documentation Bug」をクリックします。すると該当するドキュメントページのパスが補完された状態で、報告用フォームが開きます。ここに要約と詳しい説明を書いて登録します。ファイルを追加することもできますので、不備がある部分のキャプチャを撮っておいてアップロードすると説明が楽かもしれません。登録するとBugs自分が登録したバグ一覧でステータスが分かるようになります。
以前は「Report Documentation Bug」をクリックするとフォームがポップアップで開くというもので、登録後のステータス変化について何のフィードバックも無かったのですが、今ではAPIの不具合と同様にBugsに登録されます。他のユーザにも見えますし、ステータスの変化も分かるので、とても便利になりました。

4.まとめ

以上が、私がFQLを扱う上で気をつけている点です。仕様変更が多かったり不具合がちょこちょこあるということがよく言われますが、ドキュメントを確かめつつ試し、不具合があれば報告まで行うことが、イライラを減らし、他の開発者の助けにもなると思います。文句を言う前にバグ報告までしっかり行いましょう。

Graph APIで新コメント欄の返信機能を扱う

c608be7283339a863201e58e151148e6

最近の仕様変更で、Facebook上のコメント欄に返信機能が追加され、スレッド表示されるようになりました。現在は移行期間中のため、一部のFacebookページと10000人以上のフォロワーを持つユーザプロフィールのコメント欄のみに適用されています。移行期間ではありますが、最近の本家開発ブログで、Graph APIを利用して仕様変更後のコメント欄を扱う方法が記載されていたので紹介します。

今までの方法

curl -X GET https://graph.facebook.com/OBJECT_ID/comments?access_token=XXXXXX

親コメントを取得

スレッド表示になったコメント欄へのコメント群のうち、返信コメントを除くものを取得します。
※Graph API Explorerで見ている限り、filter=toplevel無しでも親コメントのみが返されます。
curl -X GET https://graph.facebook.com/OBJECT_ID/comments?filter=toplevel&fields=comments&access_token=XXXXXX
{
"id": "630688080279832",
"comments": {
"data": [
{
"id": "630688080279832_110802267",
"from": {
"category": "Website",
"name": "Oklahomer",
"id": "204277149587596"
},
"message": "てすと",
"can_remove": true,
"created_time": "2013-03-28T13:33:30+0000",
"like_count": 0,
"user_likes": false
},
{
"id": "630688080279832_110823290",
"from": {
"category": "Website",
"name": "Oklahomer",
"id": "204277149587596"
},
"message": "123456",
"can_remove": true,
"created_time": "2013-04-06T12:31:50+0000",
"like_count": 0,
"user_likes": false
}
],
"paging": {
"cursors": {
"after": "Mg==",
"before": "MQ=="
},
"next": "https://graph.facebook.com/630688080279832/comments?limit=25&after=Mg=="
}
}
}

返信コメントを取得

上述した方法で任意のオブジェクトに紐づくトップレベルのコメントIDを取得できたので、以下の要領で返信を取得します。
curl -X GET https://graph.facebook.com/COMMENT_ID/comments?access_token=XXXXXX
コメントに対するcommentsコネクションで、コメントに紐づくコメント群を取得するわけですね。

{
"data": [
{
"id": "630688080279832_110802269",
"from": {
"category": "Website",
"name": "Oklahomer",
"id": "204277149587596"
},
"message": "返信!",
"can_remove": true,
"created_time": "2013-03-28T13:33:52+0000",
"like_count": 0,
"user_likes": false
}
],
"paging": {
"cursors": {
"after": "MQ==",
"before": "MQ=="
},
"next": "https://graph.facebook.com/630688080279832_110802267/comments?limit=25&after=MQ=="
}
}

一度に両方取得する

開発ブログで紹介されていたのは上述の方法ですが、親コメント一覧を取得し、さらに個々の親コメントに紐づく返信コメントを取得して行くというのは非効率なので、これを1度にまとめる方法も紹介します。

ここまでで、/OBJECT_ID/comments と /COMMENT_ID/comments の2種類のエンドポイントが出てきました。やっていることは以下の通りです。
  1. 任意のオブジェクトのcommentsコネクションで、オブジェクトに紐づくコメントを得る
  2. 得たコメントオブジェクトのcommentsコネクションで、コメントオブジェクトに紐づくコメント群を得る
オブジェクトにぶら下がったコネクションと、それらコネクションにぶら下がるコネクションを取得する。こういったことはField Expansionが得意とするところです。
curl -X GET https://graph.facebook.com/OBJECT_ID?fields=comments.filter(toplevel).fields(id,message,from,can_remove,created_time,like_count,user_likes,comments)&access_token=XXXXXX
これで返されるデータは以下の通りです。
見てみると、ID: 630688080279832のオブジェクトに対して、「テスト」と「123456」というコメントが付けられ、「テスト」コメントに対しては「返信!」という返信コメントが付いていることが分かります。
{
"id": "630688080279832",
"comments": {
"data": [
{
"id": "630688080279832_110802267",
"message": "てすと",
"from": {
"category": "Website",
"name": "Oklahomer",
"id": "204277149587596"
},
"can_remove": true,
"created_time": "2013-03-28T13:33:30+0000",
"like_count": 0,
"user_likes": false,
"comments": {
"data": [
{
"id": "630688080279832_110802269",
"from": {
"category": "Website",
"name": "Oklahomer",
"id": "204277149587596"
},
"message": "返信!",
"can_remove": true,
"created_time": "2013-03-28T13:33:52+0000",
"like_count": 0,
"user_likes": false
}
],
"paging": {
"cursors": {
"after": "MQ==",
"before": "MQ=="
},
"next": "https://graph.facebook.com/630688080279832_110802267/comments?limit=25&after=MQ=="
}
}
},
{
"id": "630688080279832_110823290",
"message": "123456",
"from": {
"category": "Website",
"name": "Oklahomer",
"id": "204277149587596"
},
"can_remove": true,
"created_time": "2013-04-06T12:31:50+0000",
"like_count": 0,
"user_likes": false
}
],
"paging": {
"cursors": {
"after": "Mg==",
"before": "MQ=="
},
"next": "https://graph.facebook.com/630688080279832/comments?filter=toplevel&fields=id,message,from,can_remove,created_time,like_count,user_likes,comments&limit=25&after=Mg=="
}
}
Field Expansionの詳細についてはField Expansionの和訳や、「Graph APIを利用する」を参照してください。
記事検索