IT・技術研修ならCTC教育サービス

サイト内検索 企業情報 サイトマップ

研修コース検索

コラム

Ruby & Rails

CTC 教育サービス

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  OpenStack  システムトラブルシュート 

第18回 Grape ~Rubyで簡単REST~ その2 (松永紘) 2014年12月

 前回の内容からしばらく間があき、Ruby、Railsもさまざまなアップデートリリースが行われています。
直近のものではRubyが2.1.4(*1)、Railsはそれぞれ3.2.20、4.0.11、4.1.7(*2)、また4.2系のbeta版として4.2.0.beta4(*3)がリリースされました。安定版のリリースはセキュリティフィックスのようですので、早めにアップデートすることをお勧めいたします。

 さて前回はRubyでRESTfulなWebAPIを構築するためのライブラリ「Grape」をご紹介し、簡単な検索APIを実装してみました。今回はその続きとして以下のような機能を実装してみたいと思います。

  1. 登録・削除APIの実装
  2. バリデーションの実装
  3. Basic認証の実装

fig01

動作環境は前回同様、以下の通りです。(*4

  • Windows 7
  • Chrome 36
  • Ruby 2.1.2
  • Rails 4.1.4
  • Grape 0.8.0
検索APIの修正

 さっそく登録・更新APIの実装といきたいところですが、その前に少しばかりソースを修正しておきましょう。「app/api/zip_api.rb」を以下のように修正します。

class ZipAPI < Grape::API
  format :json
  helpers do
    def search_address
      Zip.where(zip_code: params[:zip_code]).first
    end
    def not_found_error
      error!("404 Not Found", 404)
    end
  end
  namespace "zip/:zip_code" do
    get do
      zip = search_address
      if zip
        zip.to_json
      else
        not_found_error
      end
    end
  end
end

この修正では郵便番号が見つからない場合のエラー処理の追加、及びモデルへの検索処理を別メソッドへ切り出しています。
ここで利用したメソッドのうち、特筆すべきものについて以下に一覧を示します。

メソッド
helpers(new_mod=nil, &block) 引数&block定義内にヘルパーメソッドやグルーピングしたい処理を記述する。
[new_mod]
上記の処理を定義したモジュールを指定
[block]
上記の処理を定義
error!(message, status=nil, headers=nil) 処理をエラーとしてレスポンスを返送する。
[message]
返送するエラーメッセージを指定
[status]
返送するステータスコードを指定(未指定時は500)
[headers]
レスポンスヘッダに追加する情報をHashで指定
namespace(space=nil, options={}, &block) ブロック内の処理にパスプレフィックスを設定する。
[space]
パスプレフィックスを指定
[options]
パスプレフィックス内のルートパラメータ設定するバリデーションを指定
[&block]
パスプレフィックスを設定する処理を定義
1.登録・削除APIの実装

 それでは登録・削除APIを実装していきましょう。「app/api/zip_api.rb」を以下のように修正します。

class ZipAPI < Grape::API
  format :json
  helpers do
    def search_address
      Zip.where(zip_code: params[:zip_code]).first
    end
    def not_found_error
      error!("404 Not Found", 404)
    end
    # 以下を追加
    # 追加処理用のヘルパーメソッド
    def add_zip
      zip = search_address || Zip.new(zip_code: params[:zip_code])
      zip.update(address: params[:address])
    end
    # 以下を追加
    # 削除処理用のヘルパーメソッド
    def remove_zip
      zip = search_address
      zip.destroy if zip
    end
  end
  namespace "zip/:zip_code" do
    get do
      zip = search_address
      if zip
        zip.to_json
      else
        not_found_error
      end
    end
    # 以下を追加
    put do
      add_zip
      status 204
    end
    # 以下を追加
    delete do
      if remove_zip
        status 204
      else
        not_found_error
      end
    end
  end
end

helpersメソッドのブロック内ではモデルの登録(更新)処理を呼び出すadd_zipと、モデルの削除処理を呼び出すremove_zipの2つのメソッドを定義しています。その上でそれぞれの処理をHTTPリクエストで受けられるように、putメソッドとdeleteメソッドを使用しています。
 それでは動作確認を行ってみましょう。今回も前回同様APIらしく開発者ツールのコンソールよりXMLHttpRequestを利用してアクセスしてみます。以下のJavaScriptを実行してみましょう。

// 登録処理
var xhr_put = new XMLHttpRequest;
xhr_put.open("put", "http://localhost:3000/zip/171-0022");
xhr_put.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr_put.send("address=東京都豊島区南池袋");
// 削除処理
var xhr_del = new XMLHttpRequest;
xhr_del.open("delete", "http://localhost:3000/zip/171-0022");
xhr_del.send();

 登録後、削除後でそれぞれ前回の参照用のJavaScriptを実行するときちんと登録(更新)もしくは削除されていることがわかるかと思います。
ここで利用したメソッドのうち、特筆すべきものについて以下に一覧を示します。

メソッド
status(status=nil) 返送するステータスコードを指定する。
[status]
ステータスコードを指定
2.バリデーションの実装

 続いてバリデーションを実装してみます。登録のPUTリクエストを受けた際、以下のリクエストパラメータの入力値チェックを行います。

  • zip_code : 必須、フォーマットが「^\d{3}-\d{4}$」であること
  • address: 必須

 それでは「app/api/zip_api.rb」を編集しましょう。既存のputメソッド呼び出しの上に、paramsメソッドの呼び出しを追加します。

class ZipAPI < Grape::API
  (略)
    # 以下の4行をputメソッド呼び出しの上に追加
    params do
      requires :zip_code, type: String, regexp: /^\d{3}-\d{4}$/
      requires :address, type: String
    end
    put do
      add_zip
      status 204
    end
  (略)

 paramsメソッドのブロック内にバリデーションの処理を記述していきます。バリデーションには以下のメソッドとメソッドの引数を設定することができます。

メソッド
requires(*attrs, &block) 入力必須とするパラメータと入力チェックを行うパラメータを指定する。
[*attrs]
第一引数に入力必須とするパラメータ名を指定
第二引数以降にチェックオプションをHashで指定(後述)
[&block]
リクエストパラメータがネストしている際、ネスト内パラメータの入力チェックを定義(以下のようなリクエストパラメータ)
{name:
{given_name: "Hiroshi",
family_name: "Matsunaga"}
}
チェックオプション
type 入力タイプをクラスで指定
values 入力を制限する項目を指定
regexp 入力チェックを行う正規表現を指定
default 入力がなかった場合のデフォルト値を指定
3.Basic認証の実装

 最後に簡単な認証機構として、Basic認証を導入してみたいと思います。ここでは登録及び削除リクエストに対してBasic認証を設定してみます。「app/api/zip_api.rb」を以下のように編集します(*5)。

class ZipAPI < Grape::API
  (略)
  group do
    # 以下の3行をgroupメソッドのブロック定義内に追加
	http_basic do |user_name, password|
      {"user" => "pass"}[user_name] == password
    end
    params do
      requires :zip_code, type: String, regexp: /^\d{3}-\d{4}$/
      requires :address, type: String
    end
  (略)

 編集が終わったら前述した登録処理のJavaScriptを実行してみましょう。下記のように認証用のダイアログが出てくるかと思います(*6)。

fig02

認証ダイアログにユーザ名とパスワードを入力してもいいですが、せっかくなのでJavaScriptを少し改変します。

// 登録処理
var xhr_put = new XMLHttpRequest;
// コネクションオープン時にユーザ名、パスワードを指定
xhr_put.open("put", "http://localhost:3000/zip/171-0022", true, "user", "pass");
xhr_put.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr_put.send("address=東京都豊島区南池袋");

上記のJavaScriptを実行すると、きちんと登録処理が行われるかと思います。

まとめ

 前回・今回と2回にわたってGrapeの紹介をいたしました。前回も書きましたがRailsアプリケーションは勿論のこと、Rackアプリケーションであれば手軽にWebAPIを作成することができますので、是非お試しください。

 それでは、Enjoy Ruby!

注釈

*1 : https://www.ruby-lang.org/ja/news/2014/10/27/ruby-2-1-4-released/

*2 : http://weblog.rubyonrails.org/2014/10/30/Rails_3_2_20_4_0_11_4_1_7_and_4_2_0_beta3_have_been_released/

*3 : http://weblog.rubyonrails.org/2014/10/30/Rails-4-2-0-beta4-has-been-released/

*4 : 執筆時のそれぞれの最新版、Chrome38、Ruby2.1.4、Rails4.1.7、Grape0.9.0でも動作確認をしています。

*5 : ここではユーザ名("user")、パスワード("pass")をソースコード上に記載していますが、当たり前ながら普通はDBなどから取得することになると思います。

*6 : 削除リクエストでも同様に、認証ダイアログがでてきます。

 


 

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  OpenStack  システムトラブルシュート