前回の記事では、Rails2.0の足回りを簡単に概観しました。今回は、実際にRails2.0の機能を利用し、RESTfulなウェブアプリケーションを作ってみたいと思います。
RESTとは何か
Rails2.0の機能を用いて、RESTfulなアプリケーションを作るまえに―
RESTとは、いったいなんでしょうか?
という問いに対して、正確に答えるには私の知識はこころもとないです。Wikipedia日本語版のRESTの項を引いてみると、「表現可能な状態を転送するもの」と書かれてありますが、これだけ翻訳してもよくわかりませんね。用語としての初出は、2000年に、HTTPプロトコル規格の主要著者の一人であるRoy Fieldingがウェブについて書いた博士論文「Architectural Styles and the Design of Network-based Software Architectures」です。RESTとはそこでFieldingが提案した、Webのアーキテクチャにおけるいくつかの原則です。
なお、Roy FieldingはHTTPプロトコルの主要著者と言うだけでなく、IETFにおいてHTML、URIの標準化に参与した人物であり、Apacheプロジェクトの創始者で、現在もApache HTTP Serverプロジェクトを率いています。彼のことを一言で表現するとまさに、「World Wide Webの神」です。
それでは、Fieldingの論文における「RESTの原則」とはどういったものでしょうか? もっとも重要なのは以下の2点ではないかと思われます。
ステートレスなクライアントサーバ方式
RESTの原則では、HTTPのリクエストに全ての情報を含み、サーバ側に、クライアントの状態を持ちません。この原則は、情報の可視性、アプリケーションの信頼性、スケーラビリティにおいてメリットを持ちます。信頼性、スケーラビリティのもっとも単純な例として、静的なHTMLファイルを想起するとよいかもしれません。デメリットとしては、リクエストに全ての情報を持ってしまうことでデータ送信量が増加し、ネットワークのパフォーマンスの低下の発生が考えられます。
統一インターフェース(Uniform Interface)
RESTを他のアーキテクチャと区別する中心となる概念が、統一インターフェースです。「統一インターフェース」とは、コンポーネント間のやりとりの全てを、リソースを表すURIと、それにたいするHTTPのメソッドで行いましょう、ということです。
インターフェースを統一化することで、アーキテクチャはシンプルになり、コンポーネント間の作用の可視性が増します。これに対する、単純、かつ最強の例としては、HTMLとURIによるリンクによって形づくられた、World Wide Web自体を想起するとよいでしょう。デメリットはフォーマットを統一化するオーバーヘッドによる実行効率の低下です。
RESTfulなURI
RESTの統一インターフェースに対する、わかりやすいたとえとして以下のものがあります。
RESTを文と考える。すると、HTTP Methodsは動詞で、URIは名詞である。
具体的な例を挙げてみましょう。
この観点からすると、以下のようなURIに矛盾があることがわかります。
統一インターフェースとしてのRESTfulなURIとは、URIを名詞と考え、HTTPのメソッドを動詞とした際に自然な形になるものといえます。
RESTのイメージだけでもつかんでいただけましたでしょうか?
Rails2.0のRESTサポートの優れた点の一つに、それ自体がRESTの問いに対する明快な回答である、という点があります。そのため、RailsのRESTサポートを見ていくことで、RESTの概念を学習することができるという一石二鳥なメリットもあります。
Railsで作る小さなRESTful Webアプリケーション
さてこのあたりで、今回の題材として、ソーシャルブックマークの代名詞となった、del.icio.us風のブックマークアプリケーションをRESTスタイルで作ってみましょう。安易ですが小さなdeliciousということで、その名もminiciousです。
それでは早速、railsコマンドでRailsアプリケーションのフォルダを作成します。
miniciousのDBスキーマ設計
ソーシャルブックマークにはどんなデータが必要でしょうか?
del.icio.usの画面を参考にすると、最低限、「ユーザ」「ブックマーク対象のURL」「タグ」といった情報が必要でありそうなことがわかります。それでは、それらのデータを保持する最初の叩き台のモデルを作成してみましょう。
Railsでのスキーマ定義を行うMigrationファイルを作成します。
上記のコマンドの実行で、「db/migrate/001_create_tables.rb」というテンプレートファイルが作成されました。これを修正してDBスキーマ設計を行います。
今回のMigrationでは、Rails 2.0から採用になったSexyMigrationの機能を利用してみましょう。Rails2.0以前のMigrationとどこが異なるのかについて見ていきます。
Rails2.0以前ではカラムの数だけ、Migrationに設定行が必要でした。Rails2.0のSexyMigrationではこうなります。
:型名ではなく、t.型名 :カラム名...の可変長の形式の指定が可能になりました。これによって設定の行数を削減することができます。
SexyMigrationはそれだけではありません。
:has_many, :belongs_toといった関連を作成している場合の、外部キーの指定も簡単になります。
t.referencesの後に、関連元のテーブル名を単数系で指定することができます。
それではこれらの機能をもちいて、実際にMigrationファイルにDBスキーマ設計を記述していきます。
最初のDBスキーマ設計ができました。rakeコマンドを用いて、DBにテーブルを作成します。
Railsでのスキーマ設計はここで終了ではなく、開発を進めていく上で矛盾が発生すれば、その都度あらたなMigrationファイルを作成し、データベースリファクタリングをすすめていくスタイルになります。
Modelの作成と関連の指定
同様にモデルの作成と、関連の指定も行います。こちらについては、Rails2.0以前と同様ですのでコード例だけにとどめます。
さきにMigrationファイルを一括して作成したため、それぞれのModel作成では--skip-migrationオプションを指定し、Migrationテンプレートの作成をスキップしています。
RESTful scaffold
前回の記事でも利用しましたが、Rails2.0以降で標準となった、RESTfulなscaffoldを利用して足がかりを作成しておきましょう。ここでも、--skip-migrationオプションを指定しています。
RESTfulなログイン
実は、ここまでの段階で、RESTfullなブックマークのCRUDを行うアプリケーションは出来てしまっています。RESTであるかどうかなどはほとんど気にせず、すんなりRailsが私たちをRESTの世界に運んでくれます。
手が止まるのは、ソーシャルブックマークの次の一歩。ログインです。
RESTの概念と、ログインすなわち認証の枠組みは相性が悪いことで知られています。「サーバ内で認証済み」という状態そのものであるログインと、サーバ側では状態を持たず、全てのリクエストに情報を持つRESTのそりが合わないのはある意味当然です。この問いに対してRailsではどう回答するのでしょうか?
今回述べる一つの解は、以下のものです。
- WebブラウザからのHTMLフォーム経由のアクセスの際はHTTPセッションを利用する
- RESTfulなURIに対するXMLアクセスの際はHTTPヘッダによるベーシック認証を利用する
サーバ側で状態を持たないはずのRESTでセッションを使ってしまっていますが、Web APIとしてだけの提供だけではなく、Webアプリケーションとしても動作させる場合、現状これが現実解ではないかと思われます。
セッションによるログイン
具体例を見てみましょう。
HTML経由のアクセスの場合はHTTPセッションを使います。ログイン用のモデルを持たない、SessionControllerを作成し、ログインした際にcreateアクションでセッションの作成、ログアウトの際にはセッションを削除するdestroyアクションを追加します。
SessionControllerを使うために必要なRouting設定は以下のようになります。前回も少し触れましたが、map.resources、map.resourceがRails2.0でRESTfulなCRUDを行うURIを作成する魔法です。次回、ActiveResourceの解説の際に詳しく説明します。
rakeのroutesコマンドで、上記のRoutingで作成したURIを可視化してみます。map.resouces,map.resourceが自動でRESTfulなURIを作成していることがわかります。
通常、統一インターフェースを最重要とするRESTfulなサービス開発では、リソース設計、URI設計にもっとも重きを置かれています。ですがRailsでは、map.resources,map.resourceを使うことで、なにも考えずにRailsの規約に従ったRESTfulなURIが作成されます。
Basic認証によるログイン
次は、RESTfulなURIに対するBasic認証です。
ここで特に重要なのはlogin_requiredメソッドです。RESTfulなURIへのXMLでのアクセスの場合、HTTPのヘッダを利用してRESTfulなリクエストの認証を行います。認証できなかった場合、再度ログインを促します。
それではlogin_requiredメソッドを解説します。
まず、respond_toが、RailsでURIのリソースの表現の違いを処理する、RESTfulなWebアプリケーションにとって非常に重要なメソッドです。上の例ではURIに対するHTMLリソースへのアクセスは、login_path (/login)に飛ばしています。
また、HTTP Basic認証の補助処理を行うヘルパーメソッドauthenticate_with_http_basic, request_http_basic_authenticationを使用しています。これらのメソッドは、Rails バージョン 2.0.2の場合、actionpack-2.0.2/lib/action_controller/http_authentication.rbにてHttpAuthenticationというmoduleとして定義されています。上の例では、authenticate_with_http_basicメソッドで認証を受け取り、request_http_basic_authenticationメソッドで認証を要求します。
認証を利用する側の、LinkControllerでは以下の修正を行います。例では、全てのアクションに対して認証のフィルターをかけています。
RESTfulなURIに対するXMLリソースへのアクセス
ここまでの段階で、RESTfulなURIにたいして、認証込みのアクセスが可能かどうかためしてみましょう。
なにはともあれ、script/severでRailsサーバを立ち上げます。
Basic認証は、HTTPのAuthorizationヘッダーに、user:passwordをBASE64でエンコードした文字列を付与することで行います。
loginのIDがuser、passwordがuserの場合、以下のようなRubyワンライナーでAuthorizationヘッダーに設定する文字列を作成できます。
ここでは、GNU wgetコマンドをもちいてアクセスしてみます(既にデータは作成済みと仮定します)。
なお、Authenticateヘッダーではなく以下のURIでも同様にBasic認証が行えます。テスト中に簡易に確認したい場合は便利です。
ERbファイルの修正
最後に、scaffold で自動作成された ERbファイルを修正してデザインを整えていきます。具体的な修正点は以下のファイルです。注意点として、layoutファイルを、application.html.erbとして一つにまとめています。
画面イメージとソースコード
以下がログイン画面です。ログイン画面で「ログインのID」「パスワード」を入力すると、リンク一覧画面にリダイレクトされます。
作成したリンクの一覧は以下のように表示されます。
なお、以下が現段階のminiciousソースアーカイブです。ログインID:user, パスワード:user のユーザが作成されています。
現在ユーザ管理の画面が無いため、別のユーザアカウントを作成したい場合、直接 SQL 文でインサートを行うか、コンソールでUserオブジェクトを作成する必要があります。
以下は、ログインID: gihyo, パスワード:gihyo のユーザ作成例です。
まとめと次回予告
Rails2.0のRESTサポートの紹介とともに、最低限の機能を持つ、RESTfulなソーシャルブックマークを作ってみました。
次回は、今回作成したアプリケーションをRails2.0の機能を用いてさらに改良していきたいと思います。