はじめに
SinatraやRamazeといったRubyのWebアプケーションフレームワークに興味をお持ちの方であれば、Rackという名前をしばしば目にしているかもしれません。どうやら様々なフレームワークに使われているらしいのだけど、そいつが一体なんなのかよくわからない、そんなあなたのために今日はそのRackをご紹介したいと思います。
様々なフレームワーク、様々なアプリケーションサーバ
しばらく前なら、Ruby on Railsブームの真っ只中、Rubyと言えばRails、Webアプリケーションを作るならRails、といったイメージを持たれていた方も多かったと思います。実際にWebアプリケーションを作ったり、Rubyに触れたりしたきっかけがRailsだったという方も多いでしょう。
しかし最近は、RubyのWebアプケーションフレームワークと一口に言っても、非常に簡単にアプリケーションが書けてしまうことで人気が出たSinatra、シンプルな構成でスッキリしたフレームワークのRamaze、いくつもの優れた特徴が逆輸入されRails3で統合を果たすことになったMerbなど、比較的メジャーなものでも次々挙げられる程に増えてきています(もちろん他にも様々あります)。
また、筆者がRailsを使った仕事をしていた頃は、MongrelかFastCGI+WebサーバでRailsを動かす構成が一般的だったのですが、最近ではThinやEbbなどの高速なアプリケーションサーバや、Apacheやnginxにモジュールとして組み込めるPhusion Passengerといったように、こちらも様々な選択肢が出てきています。
こうしてRubyによるWebアプリケーションの開発環境が増えてきた背景には、もちろんデファクトスタンダードであったRailsやMongrelの抱えていた問題を解消するために後発のプロジェクトが現われたということもありますが、その中で重要な役割を果たしている要素の一つにRackがあります。「だから、そのRackやらが果たした役割ってのはなんなのさ」という質問に答える前に、もう一つだけ先に、WSGIの話をしたいと思います。
WSGI、Rack、PSGI
WSGIとは、PythonのためのWebサーバとWebアプリケーション/フレームワーク間の標準インターフェースを定める「仕様」です。WSGIが提唱された背景には、当時既にPython製のWebアプリケーションフレームワークが百花繚乱…言い方を変えると乱立している状況だったことがあります。フレームワークは多数存在していたものの、フレームワークの実装は特定のWebサーバに依存していることが多く、使用したいフレームワークの為に環境を制限される、あるいは使用したいWebサーバの為にフレームワークを縛られる、ということが往々にしてありました。とはいえ、多数存在するサーバとアプリケーション/フレームワークがお互いに複数の環境に対応するためには、開発者にも結構な負担がかかります。そのため、両者間の標準インターフェースが提唱され、WSGIに対応しているフレームワークと、WSGIを介して連携できるWebサーバとをユーザが好みの組み合わせで使えるようになったのです。
RackはこのWSGIに影響されて開発された、Rubyにおけるサーバとアプリケーション/フレームワーク間のインターフェースの役割を果たすライブラリです。ここでようやくRackの果たす役割が見えて来ましたね。つまり、様々なアプリケーションサーバやフレームワークが開発されても、双方がRackを使用してインターフェース部分を実装していさえすれば、既存のWebアプリケーションをサーバ側の構成を変えることなく新しいフレームワークでリプレイスしたり、あるフレームワークで実装されたアプリケーションを様々な環境に移したり、といったことが容易になります。この「インターフェースが統一されていれば、サーバやフレームワークの組み合わせは自由である」ということが、選択肢の広がった最近のRubyにおけるWeb開発環境にとって重要な意味を持っているのです。
同じような流れは、今Perlでも起っています。WSGIやRackに影響を受けて、PerlでもHTTP::Engineというサーバ・アプリケーション間のインターフェースにあたるライブラリが開発されていましたが、今はそこから派生して、PSGIと呼ばれる、Perl版WSGIと言える仕様を考えるプロジェクトが始まっています。
最初のRackアプリケーション
さて話が長くなってしまいましたが、実際に簡単なRackアプリケーションを作ってRackのインターフェースに触れてみます。といっても、Rackの根幹になる部分は非常にシンプルです。Rackアプリケーションとして最低限必要なのことは次の通りです。
- callというメソッドを持っていること
- callメソッドの引数としてWebサーバからのリクエストを受けること
- callメソッドは、次の要素を含むレスポンスを返すること
- ステータスコード
- レスポンスヘッダ(Hash)
- レスポンスボディ(Array)
そこで、上記の仕様を含めた、以下のアプリを作ってみました。
実にシンプルですね。ここまで、WebサーバどころかRackに依存するコードは一切入っていません。上記のコードではインスタンスメソッドとしてcallを実装していますが、「一つ以上の引数を受けつけるcallメソッドを持っているオブジェクト」であれば何でもいいので、クラスやモジュールのメソッドでも、Procオブジェクトでも構いません。あまり制約が多くなく、pure rubyなコードとして書けることもポイントの一つです。
このコードをsimple_app.rbという名前で保存したら、今度はconfig.ruというファイルに次のように書いてください。
これで準備完了です。Rackをインストールするとrackupというコマンドも一緒にインストールされていますので、simple_app.rbとconfig.ruがあるディレクトリでrackupを実行してください。そうするとWEBrickが立ち上がるので、http://localhost:9292/にアクセスしてみましょう。先ほどのアプリケーション(と呼ぶにはあまりに簡単なものですが)が動いているのが確認できるはずです。
さて、最初は何もオプションを付けずにrackupを実行しましたが、ThinやMongrelがインストールされているのであれば、今度は rackup -s thin などとサーバを指定して実行してみてください。今度はWEBrickの代わりに-sオプションで指定したサーバが立ち上がるはずです。
以上の説明でお分かりいただけたかと思いますが、たったこれだけのコードで「様々な環境で動かせるWebアプリケーション」ができるのです。実際のWebアプリケーションフレームワークはもちろんもっと複雑なことをしていますが、「Rackアプリケーション」の仕様に則っている点では同じです。こうしてWebサーバやそのブリッジに依存するコードをアプリ側に書かないで済ませられるお陰で、様々なサーバ上で動かすことができるようになります。
というわけで、今回はRackとは何かをご紹介しましたが、次回はRackの便利な機能やアプリケーションのテストの仕方などを、実際に作りながら解説したいと思います。