stompserver の RESTful なインターフェース


前回の続きです。
stompserver に RESTful な口があるようなので今回はそちらを見てみます。


まずは、bin/stompserver を弄ります。
$HTTP_ENABLE をtrue にするだけです。これで、http.rb が読みこまれ、HTTPハンドラが開始されます。

- $HTTP_ENABLE = false
+ $HTTP_ENABLE = true

If $HTTP_ENABLE
  require 'mongrel'
  require 'stomp_server/protocols/http'
end

...

  if $HTTP_ENABLE
    puts "Http protocol handler starting on #{config.opts[:host]} port 8080"
    EventMachine.start_server(config.opts[:host], 8080, StompServer::Protocols::Http) {|s| s.instance_eval {
        @@auth_required=stomp.auth_required
        @@queue_manager=stomp.queue_manager
        @@topic_manager=stomp.topic_manager
        @@stompauth = stomp.stompauth
      }
    }
  end


で、stompserver を再起動しましょう。
うまく HTTP ハンドラが動きだしたようです。

% stompserver -p 61613 -b 0.0.0.0 -q file -s .stompfile
Queue initialized in /Users/kiwamu/work/temp/stomp/.stompfile
TopicManager initialized
QueueManager initialized
Stomp protocol handler starting on 0.0.0.0 port 61613
Http protocol handler starting on 0.0.0.0 port 8080


深く考えずにブラウザからたたいてみます。

すると、ブラウザに "No messages in queue" と表示されました。
HTTP でメッセージを send するのはさておき、前回の手順で stomp (プロトコル) でつっこんで、同様にブラウザから確認してみると、やはり "No messages in queue"...
たぶん、宛先に設定しているキューの名前を URL にするんだろうなぁと思いつつ、試してみるとちゃんと返ってきました♪


今度はブラウザに "Hello, world!" と表示されています。
もうひとつメッセージを send してから上の URL をたたいてみると、やはり "Hello, world!" とだけ表示されます。

HTTP GET するたびにメッセージを消費しているようですね。
メッセージを新しく send せずにもう一度 URL をたたくと、"No messages in queue" となりました。


ここまできてふと...わざわざブラウザ動かすまでもなかったか、と... (^^;

% irb
>> require 'net/http'            
=> []                            
>> Net::HTTP.version_1_2
=> true                         
>> Net::HTTP.start('localhost', 8080) {|http|
?>     response = http.get('/queue/test')
>>   puts response.body          
>>   }                           
No messages in queue             
=> nil           

では、HTTP でメッセージを send してみます。

% irb
>> require 'net/http'
=> []                             
>> Net::HTTP.version_1_2
=> true                          
>> Net::HTTP.start('localhost', 8080) {|http|
?>     response = http.post('/queue/test', 'Hello, world! from HTTP')
>>   }                            
=> #<Net::HTTPInternalServerError 500 Server Error readbody=true>


あれれ...500 番が返ってきました?
stompserver/protocols/http.rb をながめてみると、HTTP POST ではなく PUT を受けつけるようになっています。つまり、メッセージを send するには HTTP PUT で投げる必要があるとのこと。Web リソースの CRUD って C は POST じゃなかったでしたっけ? ん???

不本意ながら HTTP PUT してみると、ちゃんとメッセージがキューにはいりました。

>> Net::HTTP.start('localhost', 8080) {|http|
?>     response = http.put('/queue/test', 'Hello, world! from HTTP')
>>   }                            
=> #<Net::HTTPOK 200 OK readbody=true>


GET してみると、たしかにメッセージがありました。

>> Net::HTTP.start('localhost', 8080) {|http|
?>     response = http.get('/queue/test')
>>   puts response.body
>>   }                            
Hello, world! from HTTP          
=> nil


Stomp のヘッダー部に載る情報の解析は、現時点では実装されていないものの、HTTP だけでメッセージが送れるってのは使いどころの幅が広がりますね。

AP4R でも今後、RESTful なインターフェースを用意していく予定です。




追記: 2007.11.15
subscribe するのに HTTP GET を使っている点をスルーしてましたが、これも HTTP の仕様としてはおかしいですね。GET ではリソースに対して副作用をもたないはずなので、メッセージを閲覧するだけならともかく、消費してしまうのはまずいです。
ちょっと前に ActiveMQ の REST 対応でも、似たような話題が Paul Winkler さんから指摘されてました。

  • rest-discuss : Message queues

http://tech.groups.yahoo.com/group/rest-discuss/message/8955


it's not REST that says GET is a read-only operation; it's HTTP. So
their HTTP implementation is broken. Sadly seems to be pretty common.


DELETE on a URL representing a queue means you want to delete the
entire queue, not a single message!

その結果、ActiveMQ の REST 対応の仕様もこんな感じに変化しているっぽいです。たしかに、上の指摘を受けて変わってきています。

  • Apache ActiveMQ -- REST 対応のいつくかの方法を検討中 (May 05, 2006)

http://activemq.apache.org/rest-protocols.html

  • Apache ActiveMQ -- 簡単に実装してみたもの (Feb 23, 2007)

http://activemq.apache.org/rest.html

  • Apache ActiveMQ -- 考えなおしてみたもの (Aug 20, 2007)

http://activemq.apache.org/restful-queue.html