AWDwR "Chapter20 Web Services on Rails"
Chapter20を書いた人&Action Web Serviceのコード書いた人は南アフリカの人だって。Chapter18書いた人はオーストリアだし、DHHはデンマークだし、グローバルだね。
Action Web Serviceは長いんでAWSと省略するよ。
What AWS Is (and What It Isn't)
AWSではSOAPやWSDLのW3Cの仕様を全部実装したりXML-RPCの機能を全て提供するつもりはなくて、その代わりWebサービスで使いたい機能にフォーカスしている。このAWSを使うと
The API Definition
AWSを使う時に問題となるのは、Rubyのメソッドは任意の型を返すことができるけれど、受け取り側がRubyのようなダイナミックな言語じゃない場合は想定していない型が返ってくるとエラーになっちゃうこと。そこで型をちゃんと定義しておくためのAPI定義クラスというのを用意しておきました。これも以下のようにジェネレータを使うと自動生成できる。
ruby script/generate web_service Backend find_all_products find_product_by_id
こうするとスタブAPI定義のBackendApiというクラスとスケルトンコントローラのBackendControllerというクラスとそれから機能テスト用のBackendApiTestというクラスができる。
コントローラでは、wsdl_service_name()メソッドでWSDLで使われる名前を設定し、web_service_scaffold()で開発時にWebブラウザからWebサービスを呼べる機能を追加する。
API定義はapi_method()メソッドを使って行なう。引数や戻り値の型の指定はシグナチャで指定。api_method()メソッドは引数の型を指定する:expectsと戻り値の型を指定する:returnsの2つのオプション受け取り、:expectsを省略した場合はリモートから引数付で呼び出されるとエラーとなり、:returnsを省略した場合はリモートへは何も返さない。
で、定義の仕方なんだけど、まず基本型は以下のようなシンボルで指定する。
- :int 整数型
- :string 文字列型
- :base64 Base64でエンコードしたバイナリ
- :float 浮動小数点型
- :time タイムスタンプ型。RubyではTime
- :datetime タイムスタンプ型。RubyではDateTime
これら以外にもActionWebService::StructやActiveRecord::Baseのオブジェクトをシグナチャとして使うことができる。
で、シグナチャの書き方の例
- [ [:string] ] 文字列の配列
- [:bool] ブーリアン型
- [Person] Person型
- [{:lastname=>:string}] lastnameという名前つきの文字列型
- [:int, :int] 2つの整数型
Dispatching Modes
リモートからのリクエストとメソッドを結びつけるのがディスパッチなんだけど、デフォルトのディスパッチモードはDirect Dispatching。これを使う場合は特に設定は不要。Direct Dispatchingの場合、API定義は直接コントローラに結び付けられ、APIメソッドはコントローラのパブリックなインスタンスメソッドとして実装する。この方法はシンプルなんだけど、一つのAPI定義しかコントローラに結び付けられないのが欠点。Layered Dispatchingは一つのコントローラに全てのAPIを結び付け、Delegated DispatchingはいくつかのAPIを一つのコントローラに結びつける。このディスパッチングモードはコントローラ内でweb_service_dispatching_mode()で指定できる。
Using Alternate Dispatching
Layered Dispatchingを使う場合はリクエストと呼び出すメソッドのマッピングをweb_serevice()メソッドで定義しておく。Delegated Dispatchingもweb_service_dispatching_mode()に:delegateを指定する以外は同じ。
Method Invocation Interception
AWSにはリクエストの前または後で起動されるコールバックを登録することができるbefore_invocation()とafter_invocation()というのがあって、ActionPackのフィルタと同じ感じで以下のように使う。
class BackendAuthController < ApplicationController before_invocation :authenticate protected def authenticate(name, args) ... end end
before_invocation()メソッドで呼ばれるメソッドにはインターセプトしたメソッド名とその引数の配列が渡され、after_invocation()で呼ばれるメソッドはそれ以外にインターセプトしたメソッドの戻り値が渡される。またbefore_invocation()メソッド、after_invocation()メソッドには適用するメソッド、適用しないメソッドを指定する:onlyと:exceptというオプションがある。
Testing Web Services
Railsのテスト機能をAWSでも使えるよ。ジェネレータで機能テスト用のスケルトンが生成されるのでそれを書き換えて使いましょう。invoke(method_name, *args)メソッドはWebサービスを呼び出すメソッド。ただしこのinvoke()メソッドはDirect Dispatchingのコントローラに対してのみで、Layered Dispatchingの場合はinvoke_layered()メソッド、Delegated Dispatchingの場合はinvoke_delegated()を使いましょう。
で、WSDLを取得するには以下のURLにアクセスする。
http://www.foo.com/CONTROLLER/service.wsdl
また、XML-RPCの場合はエンドポイントURLを知る必要があって、Direct DispatchingとLayered Dispatchingの場合のエンドポイントは
http://www.foo.com/PATH/TO/CONTROLLER/api
Delegated Dispatchingの場合のエンドポイントURLは
http://www.foo.com/PATH/TO/CONTROLLER/SERVICE_NAME
となる。