Amazon Product Advertising API への対応例

2009年8月15日から何やらAmazon Web Serviceの仕様が変わるみたいです。
一つの対応例として、以下にコードを記します。これでちゃんと認証されているようです。

require "openssl"
require "cgi"
require "net/http"
require "kconv"
require "base64"
require "time"

class AmazonWebService

  SID = "000000000000001"                  # Your Access Key ID
  SSID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   # Your Secret Access Key
  VERSION = "2007-01-15"

  # example:
  #   AmazonWebService.call_ecs({
  #     "Operation"=>"ItemSearch",
  #     "ResponseGroup"=>"Small,OfferSummary,Images,ItemAttributes,SalesRank,BrowseNodes",
  #     "SearchIndex"=>"Blended",
  #     "Keywords"=>keyword # in utf8
  #   })
  def self.call_ecs(options)
    options = {
      "Service"=>"AWSECommerceService",
      "AWSAccessKeyId"=>SID,
      "Version"=>VERSION,
      "Timestamp"=>Time.now.gmtime.iso8601,
    }.merge(options)

    # sort keys
    keys = options.keys.sort

    # build query string with url encoded parameters
    query = keys.map{|key| "#{CGI.escape(key).gsub(/\+/,"%20")}=#{CGI.escape(options[key]).gsub(/\+/,"%20")}"}.join("&")

    # string to sign
    string_to_sign = <<EOT.strip
GET
webservices.amazon.co.jp
/onca/xml
#{query}
EOT

    # build signature
    signature = Base64.encode64(OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, SSID, string_to_sign)).strip

    # request
    query << "&Signature=#{CGI.escape(signature)}"
    uri = URI.parse("http://webservices.amazon.co.jp/onca/xml?#{query}")
    Net::HTTP.get(uri.host, uri.request_uri)
  end

end

ほぼ実在のコードのコピペなんで、名前がおかしかったり(ecsとか)するのは勘弁してください。
SIDとSSIDは自分のアカウントの情報を入れてください。
上記クラスを定義して、

  def search(keyword)
    keyword = keyword.toutf8
    options = {
      "Operation"=>"ItemSearch",
      "ResponseGroup"=>"Small,OfferSummary,Images,ItemAttributes,SalesRank,BrowseNodes",
      "SearchIndex"=>"Blended",
      "Keywords"=>keyword
    }
    xml = AmazonWebService.call_ecs(options)
  end

のようにして使います。返り値はXMLなので適宜解析しましょう。
今回のAPIの変更でややこしい署名を入れなければならなくなったわけですが、この際はまったのが、リクエストパラメータの半角スペースは"%20"にするということと、Base64.encode64がお尻に勝手に改行をつけてしまうというところでした。

参考
Product Advertising API 開発者向けガイド リクエストの署名認証について(参考訳)
http://d.hatena.ne.jp/zorio/20090509/1241886502

追記 2009/8/2
コピペしても動きませんでした。いろんなライブラリのrequire文を追加しました。やはり生Rubyは慣れない。あとSID,SSIDに関する記述を追加。