丸山先生レクチャーシリーズ2007-2008

5,522 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
5,522
On SlideShare
0
From Embeds
0
Number of Embeds
351
Actions
Shares
0
Downloads
44
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

丸山先生レクチャーシリーズ2007-2008

  1. 1. Ruby on Rails2.0 における REST 対応 丸山先生レクチャーシリーズ ~ RESTful サービス技術の台頭~ よういちろう 2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  2. 2. 自己紹介 <ul><li>田中 洋一郎 </li></ul><ul><ul><li>株式会社エーティーエルシステムズ所属 </li></ul></ul><ul><ul><li>S2Wicket コミッタ </li></ul></ul><ul><ul><li>こみゅすけ (commusuke.eisbahn.jp) 管理人 </li></ul></ul><ul><ul><ul><li>REST API 現在実装中! </li></ul></ul></ul><ul><ul><li>Blog 「天使やカイザーと呼ばれて」 </li></ul></ul><ul><ul><ul><li>http://www.eisbahn.jp/yoichiro/ </li></ul></ul></ul><ul><ul><li>Java プログラマ( JRuby on Rails に浮気中) </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  3. 3. アジェンダ <ul><li>Ruby on Rails における REST </li></ul><ul><li>RESTful サービスへのアクセス </li></ul><ul><li>RESTful サービスの実装 </li></ul><ul><li>認証処理 </li></ul><ul><li>まとめ </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  4. 4. アジェンダ <ul><li>Ruby on Rails における REST </li></ul><ul><li>RESTful サービスへのアクセス </li></ul><ul><li>RESTful サービスの実装 </li></ul><ul><li>認証処理 </li></ul><ul><li>まとめ </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  5. 5. Ruby on Rails における REST <ul><li>Rails は MVC モデル </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. dispatcher.cgi routes.rb Controller View Model Database 呼び出す Controller を特定 O/R マッピング Model への操作と View の決定 HTML や XML のレンダリング ActionPack ActiveRecord
  6. 6. Ruby on Rails における REST <ul><li>Ruby on Rails 2.0 正式リリース </li></ul><ul><ul><li>すでに 2.0.1 がある( 2007/12/9 時点) </li></ul></ul><ul><ul><li>gem install rails => 2.0.1 </li></ul></ul><ul><ul><li>API Reference の記述量がかなり増えている </li></ul></ul><ul><ul><ul><li>http://api.rubyonrails.org/ </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  7. 7. Ruby on Rails における REST <ul><li>Rails1.2 </li></ul><ul><ul><li>ActionWebService </li></ul></ul><ul><ul><ul><li>SOAP 対応がメイン </li></ul></ul></ul><ul><ul><li>RESTful サービスを実装することはできた </li></ul></ul><ul><ul><ul><li>ActionController::Resources </li></ul></ul></ul><ul><ul><ul><li>routes.rb での map.resource(s) によるマッピング </li></ul></ul></ul><ul><ul><ul><li>script/generate scaffold_resource </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  8. 8. Ruby on Rails における REST <ul><li>Rails2.0 </li></ul><ul><ul><li>RESTful サービスの実装 </li></ul></ul><ul><ul><ul><li>script/generate scaffold が REST 標準対応 </li></ul></ul></ul><ul><ul><ul><li>AtomPub 対応 </li></ul></ul></ul><ul><ul><li>ActiveResource の標準搭載 </li></ul></ul><ul><ul><ul><li>REST クライアントを簡単に作成可能 </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 Rails 2.0 では REST がメインとなる
  9. 9. Ruby on Rails における REST 2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  10. 10. アジェンダ <ul><li>Ruby on Rails における REST </li></ul><ul><li>RESTful サービスへのアクセス </li></ul><ul><li>RESTful サービスの実装 </li></ul><ul><li>認証処理 </li></ul><ul><li>まとめ </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  11. 11. RESTful サービスへのアクセス <ul><li>ActiveResource </li></ul><ul><ul><li>Business Object と RESTful サービスの接続 </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 Business Object ActiveResource RESTful WebService 普通の Object へのアクセス 透過的なプロキシとして機能する Object と REST リソースのマッピング
  12. 12. RESTful サービスへのアクセス <ul><li>ActiveResource </li></ul><ul><ul><li>RESTful サービスなのか Database なのか </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 Business Object Active Resource RESTful WebService Object と REST リソースのマッピング Business Object Active Record Object と Database Entity のマッピング Database
  13. 13. RESTful サービスへのアクセス <ul><li>ActiveResource </li></ul><ul><ul><li>ActiveRecord と使い方は(ほぼ)一緒 </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 emp = Employee.new emp.name = ‘yoichiro’ emp. save emp = Employee. find (13308) p emp.name # => “yoichiro” emp = Employee. find (13308) emp. destroy Employee. delete (12345) emp = Employee. find (13308) emp.name = ‘yojiro’ emp. save 生成 検索 更新 削除
  14. 14. RESTful サービスへのアクセス <ul><li>ActiveResource </li></ul><ul><ul><li>例: Twitter の情報を取得 </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 class Status < ActiveResource::Base self. site = ‘http:// [ ユーザ ID]:[ パスワード ]@ twitter.com’ self. logger = Logger.new($stderr) end ActionResource::Base クラスを継承 site クラス変数にリソースの在り処を指定 リソース名をクラス名にする logger クラス変数に設定すると URL が見える HTTP BASIC 認証
  15. 15. RESTful サービスへのアクセス <ul><li>ActiveResource </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 >> s = Status.find(‘show/485685072’) => #<Status:0xb58ad1 @prefix_options={}, @attributes={&quot;text&quot;=>&quot;ActiveResource343201247343201223343201256343202271343203206343203274343343203206343202271343203210 ! &quot;, &quot;id&quot;=>&quot;485685072&quot;, &quot;source&quot;=>&quot;web&quot;, &quot;created_at&quot;=>&quot;Mon Dec 10 06:42:46 +0000 2007&quot;}> >> GET http://twitter.com:80/statuses/show/485685072.xml --> 200 OK (733b 0.34s) >> puts s.text ActiveResource でこのステータス取得をテスト! => nil
  16. 16. RESTful サービスへのアクセス 2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. Person.find(:all) # => GET /people.xml Person.find(:all, :params => { :title => &quot;CEO&quot; }) # => GET /people.xml?title=CEO Person.find(:first, :from => :managers) # => GET /people/managers.xml Person.find(:all, :from => &quot;/companies/1/people.xml&quot;) # => GET /companies/1/people.xml Person.find(:one, :from => :leader) # => GET /people/leader.xml Person.find(:one, :from => &quot;/companies/1/manager.xml&quot;) # => GET /companies/1/manager.xml StreetAddress.find(1, :params => { :person_id => 1 }) # => GET /people/1/street_addresses/1.xml
  17. 17. RESTful サービスへのアクセス <ul><li>ActiveResource </li></ul><ul><ul><li>狭義の REST 対応 Web サービス </li></ul></ul><ul><ul><ul><li>完璧にリソースをオブジェクトに関連可能 </li></ul></ul></ul><ul><ul><li>REST 準拠 Web サービス </li></ul></ul><ul><ul><ul><li>参照系はほとんど対応可能 </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 マッシュアップが非常に簡単になる
  18. 18. RESTful サービスへのアクセス <ul><li>Ajax で RESTful サービスにアクセス </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. link_to_remote &quot;Delete this post&quot;, :update => &quot;posts&quot;, :url => post_url(@post), :method => :delete , :html => { :class => &quot;destructive&quot; } ヘルパーメソッドが method 指定をサポート <a class=&quot;destructive&quot; href=&quot;#&quot; onclick=&quot;new Ajax.Updater('posts', 'http://localhost:3000/employees/3', {asynchronous:true, evalScripts:true, method:'delete' , parameters:'authenticity_token=' + encodeURIComponent('520fb86f42576048061a5c408604c52411df8841')}); return false;&quot;>Delete this employee</a>
  19. 19. RESTful サービスへのアクセス <ul><li>Ajax で RESTful サービスにアクセス </li></ul><ul><ul><li>ブラウザは GET と POST のみ発行できる </li></ul></ul><ul><ul><ul><li>PUT 、 DELETE は POST で代用 </li></ul></ul></ul><ul><ul><ul><li>_metod パラメータを使用 </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved.
  20. 20. アジェンダ <ul><li>Ruby on Rails における REST </li></ul><ul><li>RESTful サービスへのアクセス </li></ul><ul><li>RESTful サービスの実装 </li></ul><ul><li>認証処理 </li></ul><ul><li>まとめ </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  21. 21. RESTful サービスの実装 <ul><li>scaffold によるお手本コード </li></ul><ul><ul><li>Rails2.0 から REST 対応が標準になった </li></ul></ul><ul><ul><ul><li>scaffold_resources が格上げ </li></ul></ul></ul><ul><ul><ul><li>RESTful サービスをコーディングレスで入手 </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 Scaffold Code EmployeesController Employee Model Views
  22. 22. RESTful サービスの実装 <ul><li>scaffold によるお手本コード </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 $ jruby ./script/generate scaffold employee # GET /employees/1 # GET /employees/1.xml def show @employee = Employee.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml {render :xml => @employee} end end employees_controller.rb ActionController::Routing::Routes.draw do |map| map.resources :employees routes.rb
  23. 23. RESTful サービスの実装 <ul><li>scaffold によるお手本コード </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 RESTTest scaffold を生成するだけ コーディングなし
  24. 24. RESTful サービスの実装 <ul><li>Rails での標準的な REST 対応 </li></ul><ul><ul><li>HTTP Method,Path と Controller との関連付け </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 routes.rb map.resources Controller ActiveRecord Database 規則に従って、 HTTP Method および PATH から呼び出す Controller を選定 各メソッド内で ActiveRecord によりリソースを取得・更新 処理結果を HTTP Status に、リソースを XML 形式に変換して返却
  25. 25. RESTful サービスの実装 <ul><li>routes.rb でのルーティング設定 </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 ActionController::Routing::Routes.draw do |map| map.resources :employees end EmployeesController のメソッド Verb Path Method Parameter GET /employees index GET /employees/1 show :id => 1 POST /employees create PUT /employees/1 update :id => 1 DELETE /employees/1 destroy :id => 1
  26. 26. RESTful サービスの実装 <ul><li>routes.rb でのルーティング設定 </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 map.resources :divs do |divs| divs.resources :employees end EmployeesController のメソッド リソースのネスト定義 より多段にすることも可能 Verb Path Method Parameter GET /divs/1/employees index :div_id => 1 GET /divs/1/employees/2 show :div_id => 1 :id => 2 POST /divs/1/employees create :div_id => 1 PUT /divs/1/employees/2 update :div_id => 1 :id => 2 DELETE /divs/1/employees/2 destroy :div_id => 1 :id => 2
  27. 27. RESTful サービスの実装 <ul><li>GET /employees.xml </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 def index @employees = Employee.find(:all) respond_to do |format| format.html # index.html.erb format.xml { render :xml => @employees } end end routes.rb によるマッピング 「 .xml 」なので、モデルの内容が XML 形式でレンダリングされる
  28. 28. RESTful サービスの実装 <ul><li>GET /employees.xml </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 format.xml { render :xml => @employees } <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <employees type=&quot;array&quot;> <employee> <id type=&quot;integer&quot;>3</id> <name>Yoichiro Tanaka</name> </employee> ・・・ </employees> View を作らなくてもレンダリングされる
  29. 29. RESTful サービスの実装 <ul><li>GET /employees/1.xml </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 def show begin @employee = Employee.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @employee } end rescue ActiveRecord::RecordNotFound head :not_found end end routes.rb によるマッピング 「 .xml 」なので、モデルの内容が XML 形式でレンダリングされる リソースがない場合は 404 を返す
  30. 30. RESTful サービスの実装 <ul><li>POST /employees.xml </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 def create @employee = Employee.new(params[:employee]) respond_to do |format| if @employee.save format.html { redirect_to(@employee) } format.xml { render :xml => @employee, :status => :created, :location => @employee } else ・・・ end routes.rb によるマッピング 新規作成処理の結果、 ステータスコードは 201 Location ヘッダはリソースの URI を返却する
  31. 31. RESTful サービスの実装 <ul><li>PUT /employees/1.xml </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 def update begin @employee = Employee.find(params[:id]) respond_to do |format| if @employee.update_attribute(params[:employee]) format.html { redirect_to(@employee) } format.xml { head :ok } else ・・・ rescue ActiveRecord::RecordNotFond head :not_found end end routes.rb によるマッピング 更新処理の結果、 ステータスコードは 200 を返却する リソースがない場合は 404 を返す
  32. 32. RESTful サービスの実装 <ul><li>DELETE /employees/1.xml </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 def destroy begin @employee = Employee.find(params[:id]) @employee.destroy respond_to do |format| format.html { redirect_to(employees_url) } format.xml { head :ok } end rescue ActiveRecord::RecordNotFond head :not_found end end routes.rb によるマッピング 削除処理の結果、 ステータスコードは 200 を返却する リソースがない場合は 404 を返す
  33. 33. RESTful サービスの実装 <ul><li>AtomPub </li></ul><ul><ul><li>Rails2.0 から実装しやすくなった </li></ul></ul><ul><ul><ul><li>Accept や URI の拡張子による View の切り替え </li></ul></ul></ul><ul><ul><ul><li>Builder テンプレートによる XML 構築 </li></ul></ul></ul><ul><ul><ul><li>atom_feed ヘルパーメソッドの提供 </li></ul></ul></ul><ul><ul><li>リソースの扱い </li></ul></ul><ul><ul><ul><li>コレクションリソースは feed </li></ul></ul></ul><ul><ul><ul><li>メンバリソースは entry </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved.
  34. 34. RESTful サービスの実装 <ul><li>Rails での Atom 的な REST 対応 </li></ul><ul><ul><li>HTTP Method,Path と Controller との関連付け </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 routes.rb map.resources Controller ActiveRecord Database 規則に従って、 HTTP Method および PATH から呼び出す Controller を選定 各メソッド内で ActiveRecord によりリソースを取得・更新 atom.builder filter View で Atom Feed を構築して返却 リクエストの XML を params ハッシュに変換
  35. 35. RESTful サービスの実装 <ul><li>index.atom.builder </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. atom_feed do |feed| feed.title(&quot;My great blog!&quot;) feed.updated((@posts.first.created_at)) for post in @posts feed.entry(post) do |entry| entry.title(post.title) entry.content(post.body, :type => 'html') entry.author do |author| author.name(&quot;DHH&quot;) end end end end View ヘルパーを使う
  36. 36. RESTful サービスの実装 <ul><li>新規投稿リクエストの受付 </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. def parse_request_xml if /^application/atom+xml/.match( request.env[“CONTENT_TYPE”] ) xml = REXML::Document.new(request.raw_post) params[:post] = { :title => xml.elements[“ entry/title ”].text :content => xml.elements[“ entry/content ”].text } end return true end 変換ロジックは自作する このメソッドを before フィルタとしておくと良い XML をパースして、各要素から params ハッシュに格納 request.format = Mime::ATOM でも可
  37. 37. RESTful サービスの実装 <ul><li>新規投稿リクエストの受付 </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. def create @post = Post.new( params[:post] ) @post.save respond_to do |format| format.atom do headers[“Content-Type”] = “ application/atom+xml;type=entry” render :action => “show”, :status => :created, :location => post_url(@post) + “.atom” end end end parse_request_xml により params[:post] が利用可能 POST /posts.atom により format.atom が対応 新規投稿処理の結果、 ステータスコードは 201 Location ヘッダはリソースの URI を返却する
  38. 38. RESTful サービスの実装 <ul><li>show.atom.builder </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. xml .instruct! xml.entry(“xml:lang” => “ja”, “ xmlns” => “http://www.w3.org/2005/Atom”) do |entry| entry.title(@post.title) entry.content(@post.body, :type => 'html') entry.author do |author| author.name(&quot;DHH&quot;) end end Builder::XmlMarkup を使って構築
  39. 39. アジェンダ <ul><li>Ruby on Rails における REST </li></ul><ul><li>RESTful サービスへのアクセス </li></ul><ul><li>RESTful サービスの実装 </li></ul><ul><li>認証処理 </li></ul><ul><li>まとめ </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09
  40. 40. 認証処理 <ul><li>REST Web サービスで使われる認証 </li></ul><ul><ul><li>HTTP BASIC 認証 </li></ul></ul><ul><ul><li>WSSE 認証 </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved.
  41. 41. 認証処理 <ul><li>HTTP BASIC 認証 (Rails 2.0 から標準搭載 ) </li></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. class ApplicationController < ActionController::Base before_filter :authenticate protected def authenticate if request.format == Mime::ATOM if user = authenticate_with_http_basic { |u, p| @account.authenticate(u, p) } @current_user = user else request_http_basic_authentication end else request からユーザ ID およびパスワードを取得して認証を実施 認証失敗時に再度ブラウザに認証情報送信を要求 AtomPub の場合
  42. 42. 認証処理 <ul><li>WSSE 認証 </li></ul><ul><ul><li>Atom API で多く使われる認証方式 </li></ul></ul><ul><ul><li>X-WSSE ヘッダを用いて認証用文字列を送信 </li></ul></ul><ul><ul><ul><li>認証用文字列はユーザ名とパスワードを含む </li></ul></ul></ul><ul><ul><ul><li>パスワードは SHA1 によるダイジェスト </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 X-WSSE: UsernameToken Username=“yoichiro&quot;, PasswordDigest=&quot;ZCNaK2jrXr4+zsCaYK/YLUxImZU=&quot;, Nonce=&quot;Uh95NQlviNpJQR1MmML+zq6pFxE=&quot;, Created=&quot;2007-12-11T22:51:15Z&quot;
  43. 43. 認証処理 2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. require ‘base64’ def auth_wsse @@wsse_pattern ||= /^UsernameToken Username=&quot;([^&quot;]+)&quot;,sPasswordDigest= &quot;([^&quot;]+)&quot;,sNonce=&quot;([^&quot;]+)&quot;,sCreated=&quot;([^&quot;]+)&quot;$/ if request.env['HTTP_X_WSSE'] && @@wsse_pattern =~ request.env['HTTP_X_WSSE'] username = $1 passwd = Base64.decode64($2) nonce = Base64.decode64($3) created = $4 return username == ‘yoichiro‘ && Digest::SHA1.digest( nonce + created + ‘pass’) == passwd else ・・・ end 正規表現により認証情報を取得 パスワードと付加情報から SHA1 ダイジェストを生成し比較 これも before フィルタとしておけば便利
  44. 44. 認証処理 <ul><li>気になる点 </li></ul><ul><ul><li>付加情報 (nonce,created) より SHA1 を実施 </li></ul></ul><ul><ul><ul><li>サーバにパスワード「そのもの」が必要になる </li></ul></ul></ul><ul><ul><ul><li>BASIC 認証よりはマシ? </li></ul></ul></ul><ul><ul><ul><li>SHA1 の前にハッシュをしておく? </li></ul></ul></ul><ul><ul><ul><li>HTTPS + BASIC 認証が良い? </li></ul></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved.
  45. 45. まとめ <ul><li>Ruby on Rails 2.0 </li></ul><ul><ul><li>ActionWebService をあっさりと捨てた大胆さ </li></ul></ul><ul><ul><li>RESTful サービスにあっさりとアクセス可能 </li></ul></ul><ul><ul><li>RESTful 実装コードをあっさりと入手可能 </li></ul></ul><ul><ul><li>認証処理もあっさりと実装可能 </li></ul></ul>2007/12/18 (c) 2007 Yoichiro Tanaka. All rights Reserved. 05/29/09 Rails 2.0 は RESTful に最適な環境

×