--- layout: old_post title: JavaScriptによるRESTライブラリ Jester ver1.3 とJSONP対応 permalink: /tatsuya/show/344-javascript-rest-jester-ver1-3-jsonp ---

あいかわらず、JavaScriptのActiveResource的なRESTライブラリ Jester を触るのが楽しい

Jester-RESTfullなRails向けJavaScriptライブラリ:TKMR.blog.show
RESTRails 向けのJavaScriptライブラリ Jester まとめ:TKMR.blog.show
RESTアクセスを行うJavaScriptライブラリ Jester Ver.1.2の変更点:TKMR.blog.show

このJester、最近Subversionのリポジトリを見るとVer1.3が完成している(ように見える)。CHANGELOGを見るとついにJSONサポートが完了してる?早速試してみよう

ローカルサーバとJSON

まずサーバ側を用意、クレジットカードが目に入ったのでcardとかをscaffold_resourceで作る

ruby script/generate scaffold_resource card name:string number:integer

各種アクションをJSON対応させる

respond_to do |format|
 format.html
 format.xml  { render :xml => @cards.to_xml }
 format.json { render :json => @cards.to_json}
end

サーバ側終了、rake migrateしてからwebサーバ立ち上げる。
続いてクライアント側、Prototype.jsとJester.jsを読み込ませて準備完了。FireBugで触ってみる

jester-13

追記:PUT & DELETEはクエリーストリングで擬似的に投げる、_method=put みたいに

Base.model("Card",{format: "json"});

>>> Card.create({name: "Suica", number: 123311123});
POST http://localhost:3000/cards.json
  ( card[name]=Suica&card[number]=123311123 )

>>> suica = Card.find(3);
GET http://localhost:3000/cards/3.json

>>> suica.name;
"Suica"

>>> suica.name = "Pasmo";
>>> suica.save();
POST http://localhost:3000/cards/3.json
  ( card[name]=Pasmo&card[number]=123311123&card[id]=3&_method=put )

>>> suica.destroy();
POST http://localhost:3000/cards/3.json
  ( _method=delete )

文句無しの動作:)RESTfulにサーバ側を作っておけばかなり快適、実質書いたコードは10行くらいだろうか?

クロスサイトとJSONP対応

但しJSONといってもあくまでもAjax.Requestを投げ結果をevalするだけ、JSONPでクロスサイトリクエストは無理な様子(正式にリリースされていないので確信は無いですが)やっぱクロスサイトにできると楽しそうなので、まずはfindを実装してみた。あとついでにカスタムメソッドも

jester-json.js

<課題>

・findのみではなく更新系も対応(やっぱBase.requestを拡張する?)
・コールバック用の一時的な関数を作るのは微妙...
 動的生成するscriptのonLoadイベントへコールバックを設定するべき?

これで試しに Twitter / Wassr / LivedoorReaderFeedAPI / AmebaVision 等のAPIを叩いてみた

デモ画面こちらから→:http://blog.tkmr.org/jester-13-test.html

以下のようにモデルを宣言して

 class="clear"
//Twitter API
Base.model("Statuse",{format:"json", prefix:"http://twitter.com"});

//LDR API
Base.model("LDRFeed",{format:"json", plural:"feed", prefix:"http://rpc.reader.livedoor.com"});

//Wassr API
Base.model("Wassr",{format:"json", plural:"api.wassr.jp", prefix:"http:/"}); //むむむ苦肉の策

//AmebaVision API
Base.model("AmebaVision",{format:"json", plural:"api/get", prefix:"http://vision.ameba.jp"});

findを実行してみる

 class="clear"
Statuse.find("friends.json",
  {},
  {onSuccess: function(base){
    render(base, new Template("<img src='#{profile_image_url}'/><a href='#{url}'><h2>Name : #{name}</h2></a><h4>#{description}</h4>"));
}});

LDRFeed.find("discover",
  {format:"json", url:"http://www6.ocn.ne.jp/~katoyuu/"},
  {onSuccess: function(base){
    render(base, new Template("<a href='#{link}'><h2>#{title}</h2></a><h4>subscribers_count:#{subscribers_count}</h4>"));
}});

Wassr.find("public_timeline.json",
  {},
  {onSuccess:function(base){
    render(base, new Template("<a href='#{link}'><h2>#{text}</h2></a><h4>#{user_login_id}</h4>"));
}});

AmebaVision.find("recentMovie.do",
  {format:"jsonp"},
  {onSuccess:function(base){
    render(base[0].item, new Template("<a href='#{link}'><img src='#{imageUrlLarge}'/><h2>#{title}</h2></a>"));
}});

結果が表示される筈。

結局REST度が高いTwitter以外は無理矢理感が否めないか。。。この辺りRESTfulなAPIが増えていけば面白そうだと思う、JesteのやってることはまるでO/R(Object/RESTResource)マッピングだと思うのだが、世界中のWEBサービスがをオブジェクトへマッピングして自由に汎用的に扱えればかなり面白そうだ。上のFireBugでやっているようなことを世界規模でできると楽しいと思うのだけど、どうだろうか?
例えばTwitterの発言でURLを見つけたら、関連するフィードを探してLDRに登録するには

 class="clear"
statuses = Twitter::statuse.find("friend_timeline")
statuses.each do |status|
  if status.text.isURL? then
  feeds = LDR::feed.find("discover", {:url => status.text})
    feeds.each do |feed|
      LDR::account.find(myid).update("subscribe", {:url => feed.url})
    end
  end
end

等と書きたい。そのためにSOAPなんて必要ない、シンプルなRESTで十分だと思う。

JavaScriptMVC
についても書きたかったのだけど、明日に回そう。
最近リリースされたERbテンプレートライクなJavaScriptテンプレートエンジン "EJS" をViewに置いて

EJS - Embedded JavaScript at Edward Benson
ModelはJester、Controllerは...jQuery辺りを組み合わせて、Railsとの連携に向いたシンプルで簡単なMVCフレームワークが作れないかな。プラグイン式に拡張可能なやつが良いな〜、とか考えてる。

追記:正式にリリースされたぽいJester ver1.3の変更点についてメモ