LoginSignup
4
4

More than 5 years have passed since last update.

Amazon の Product Advertising API を使う

Last updated at Posted at 2014-11-22

Product Advertising API

Amazonの商品情報を検索できるAPI

公式のJava実装

Scalaで書いてみる

amazon.scala
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.{TimeZone, Calendar}
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import org.apache.commons.codec.binary.Base64
import scala.collection.SortedMap
import scala.collection.immutable.TreeMap
import scala.io.Source
import scala.collection.JavaConversions._

/**
 * Created by FScoward on 2014/11/21.
 */
class Amazon {
  private val accessKey = "秘密"
  private val secretAccessKey = "秘密"
  private val HMAC_SHA_256 = "HmacSHA256"
  private val UTF8_CHARSET = "UTF-8"
  private val REQUEST_URI = "/onca/xml"
  private val REQUEST_METHOD = "GET"
  private val endpoint = "ecs.amazonaws.jp"

  // 初期化
  val mac = {
    val secretAccessKeyBytes = secretAccessKey.getBytes(UTF8_CHARSET)
    val secretKeySpec = new SecretKeySpec(secretAccessKeyBytes, HMAC_SHA_256)
    val mac = Mac.getInstance(HMAC_SHA_256)
    mac.init(secretKeySpec)
    mac
  }

  def sign(params: Map[String, String]) = {
    val sortedParams = TreeMap.empty[String, String] ++ params ++ Map("AWSAccessKeyId" -> accessKey, "Timestamp" -> timestamp)
    val canonicalQS = canonicalize(sortedParams)
    val toSign = s"""$REQUEST_METHOD\n$endpoint\n$REQUEST_URI\n$canonicalQS"""
    val sig = percentEncodeRfc3986(hmac(toSign))
    val url = s"""http://$endpoint$REQUEST_URI?$canonicalQS&Signature=$sig"""
//    Source.fromURL(url)
    println(url)
  }

  // hmac 生成
  private def hmac(stringToSign: String) = {
    try {
      val data = stringToSign.getBytes(UTF8_CHARSET)
      val rawMac = mac.doFinal(data)
      new String(new Base64().encode(rawMac))
    } catch {
      case e: UnsupportedEncodingException => throw new RuntimeException(UTF8_CHARSET + "is unsupported!", e)
    }
  }

  // タイムスタンプ生成
  private def timestamp = {
    new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") {
      this.setTimeZone(TimeZone.getTimeZone("GMT"))
    }.format(Calendar.getInstance.getTime)
  }

  // 整形
  private def canonicalize(sortedParamMap: SortedMap[String, String]) = {
    val builder = new StringBuilder
    sortedParamMap.entrySet().iterator().foreach{ kvpair => 
      builder.append(percentEncodeRfc3986(kvpair.getKey))
      builder.append("=")
      builder.append(percentEncodeRfc3986(kvpair.getValue))
      builder.append("&")
    }
    builder.deleteCharAt(builder.lastIndexOf("&"))
    builder.toString
  }

  // + * %7E を変換
  private def percentEncodeRfc3986(string: String): String = {
    try {
      URLEncoder.encode(string, UTF8_CHARSET)
        .replace("+", "%20")
        .replace("*", "%2A")
        .replace("%7E", "~")
    } catch {
      case e: UnsupportedEncodingException => string
    }
  }
}

Scalaっぽい書き方とは?
誰か教えて下さい。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4