ザネリは列車を見送った

ブログという名の備忘録

Facebook C# SDK を F# から実行する

Facebook C# SDK を使用して F# からFacebook API を叩いてみた。
最初にコードを示しておくと、こんな感じになった。

…うーん、ダウンキャストしたりボクシングしたりミュータブルな Dictionary を使ったりと、
あんまり F# らしいイケてるコードに見えない…。
これは僕がもっと良い書き方を知らないからなのだろうか…。

SDK の入手

NuGetを使用する。
Visual Studio拡張機能としてインストールするのが一般的(?)なようだけど、
普段 Visual Studio を使っていないのでスタンドアローン版
(っていうのかな、コマンドラインで実行できるexeファイル)を使用した。

nuget install Facebook

を実行すると、まず NuGet 自体のアップデートが行われた。

NuGet bootstrapper 1.0.0.0
Found NuGet.exe version 2.5.0.
Downloading...
Update complete.

アップデート完了後、再度同コマンドを実行する。

Installing 'Facebook 6.4.0'.
Successfully installed 'Facebook 6.4.0'.
ライブラリのロード

NuGetで取得した Facebook.dll と ZaneliFacebook.fs を F# interactive にロードする。
(ついでにモジュールのインポートも)

#r "Facebook.dll";;
#load "AccessToken.fs";;

open Zaneli.Facebook;;
アプリ認証のためのcodeを取得
let url = getLoginUrl;;

で取得したURLにブラウザアクセスして、code を取得する。
認証確認ダイアログ
code はアプリ認証後、redirectUri に指定した URI に Get パラメータとして付いてくる。
パラメータに指定している appId は Facebook アプリ設定画面で確認できる「アプリID」。
redirectUri はアプリ設定画面で設定したURLと一致、もしくは App Domains で指定したドメインのサブドメインにする必要がある。
パラメータをボクシングしているのは、FacebookClient の GetLoginUrl に
IDictionary<string, string> ではなく IDictionary<string, obj> を渡す必要があるため。
(これはボクシングではなくてもっと良いやり方があるように思う…)

アクセストークンを取得

先ほど取得したcodeを引数に使用する。

let token = getAccessToken <取得したcode>;;

この token を使用して各 API を実行する。

自分のプロフィールを取得
let profile = getProfile <取得したtoken>;;

独自で定義した Profile レコードを返すようにした。
パラメータは、dict[("access_token", box token)] としたかったが、以下のエラーが発生した。

System.NotSupportedException: 種類 'System.NotSupportedException' の例外がスローされました。
   場所 Microsoft.FSharp.Core.ExtraTopLevelOperators.CreateDictionary@45.Remove(TKey key) 場所 f:\dd\fsharp\devdiv\src\fsharp\FSharp.Core\fslib-extra-pervasives.fs:行 74
   場所 Facebook.FacebookClient.PrepareRequest(HttpMethod httpMethod, String path, Object parameters, Type resultType, Stream& input, Boolean& containsEtag, IList`1& batchEtags)
   場所 Facebook.FacebookClient.Api(HttpMethod httpMethod, String path, Object parameters, Type resultType)
   場所 Facebook.FacebookClient.Get(String path, Object parameters, Type resultType)
   場所 Facebook.FacebookClient.Get(String path, Object parameters)

どうも内部で要素を除去しているらしく、イミュータブルな IDictionary では駄目なようだ。
これも Dictionary<string, obj> に要素をセットするのではなく、もう少し F# 的にスマートなやり方がある気がする。

投稿
let result = post <取得したtoken> <投稿内容>;;

レスポンスには投稿した ID が返ってくるようだ。
パラメータとしては

  • picture
  • link
  • message
  • name
  • caption
  • description
  • category

が指定できるらしいが、今回は単純にメッセージのみ指定するようにした。
投稿結果
こちらも dict 関数でパラメータを作って渡すと以下のエラーが発生した。

System.NotSupportedException: 種類 'System.NotSupportedException' の例外がスローされました。
   場所 Microsoft.FSharp.Core.ExtraTopLevelOperators.CreateDictionary@45.set_Item(TKey key, TValue value) 場所 f:\dd\fsharp\devdiv\src\fsharp\FSharp.Core\fslib-extra-pervasives.fs:行 48
   場所 Facebook.FacebookClient.PrepareRequest(HttpMethod httpMethod, String path, Object parameters, Type resultType, Stream& input, Boolean& containsEtag, IList`1& batchEtags)
   場所 Facebook.FacebookClient.Api(HttpMethod httpMethod, String path, Object parameters, Type resultType)
   場所 Facebook.FacebookClient.Post(String path, Object parameters)

こちらは内部で要素の追加をしているようだ。

 

色々改善点は残っているように思うが、とりあえず動くのを確認できたのでめでたし、としておこう。