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っぽい書き方とは?
誰か教えて下さい。