Amazon API 経由で書籍を検索する(調査編その2)

まだまだ先は長い・・・

Amazon REST API 経由で書籍を検索するための、URL クエリを生成するまでの大まかな流れメモ。

  1. パラメータを用意(TimestampとSignature以外)
  2. Timestamp を付与
  3. Signature を HMAC-SHA256 で準備(参考: Swift 4で HMAC-SHA256)
  4. Signature は base64 でエンコード
  5. Signature を base64 でエンコードした後に Signature として指定する文字列から = とかを変換(base64encodeで付いてしまう)

Amazon API 用のタイムスタンプのサンプル。

private var timestamp: DateFormatter {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.timeZone = TimeZone(identifier: "GMT")
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
    return formatter
}
print(String(format: "Now: %@", self.timestamp.string(from: Date()))

Timestamp=%@ に指定する場合は ‘-‘ (ハイフン)はOKだけど ‘:’ (コロン)はURL Query用のエンコードが必要。

URL Query 用にパラメータを個別にエンコードする場合のサンプル。

extension String {
    func urlNumericEncoding() -> String {
        if let ret = self.addingPercentEncoding(withAllowedCharacters: .alphanumerics ) {
            return ret
        }
        return ""
    }
}

上記で十分かどうかは未確認。

一通りパラメータの準備が終わり、Signature をつけたら実際にブラウザ経由などで投げてみると結果がすぐ帰ってくる。Timestamp が著しく古いとレスポンスが異様に遅い気がする。気のせいかもしれない。

この時お目見えするであろうエラーメッセージの方々。

タイムスタンプの書式がおかしいぞエラー

InvalidParameterValue
Value 2017-01-01 00:00:00 0000 for parameter Timestamp is invalid.
Reason: Must be in ISO8601 format.

Signature を検算したけど値が間違ってるぞオラー

SignatureDoesNotMatch
The request signature we calculated does not match the signature you provided.
Check your AWS Secret Access Key and signing method.
Consult the service documentation for details.

Signature 用に HMAC-SHA256 で計算した後に base64 エンコードも必要になりますが、この時に計算結果の Raw Data に対して base64 エンコードをかけないと計算結果が合わず上記エラーが返ってきます。

別記事に書いた hmac 関数の戻り値を返す際に、一緒に base64EncodedString 呼んでやると Signature に指定できる値になります。きっと。

return Data(bytes: result, count: result.count).base64EncodedString()

アクセスキー(AccessKey)がアフェリエイトサイトでの登録と連携されていないぞエラー(別途登録が必要)

AWS.InvalidAccount
Your AccessKey Id is not registered for Product Advertising API.
Please use the AccessKey Id obtained after registering
at https://affiliate.amazon.co.jp/assoc_credentials/home.

しかし、、、Signature の計算が難解だった。何度やっても計算合わないって。

ググって出てくる以下サイトのサンプルは地雷の模様。

https://affiliate.amazon.co.jp/help/topic/t126/a13

以下、被害者の会

https://forums.aws.amazon.com/thread.jspa?threadID=31670&tstart=0

いくら検算しても計算合わないしっ。コードだけではなく openssl コマンドなどでやった結果とも違うし。おかげで HMAC-SHA256 のロジックに何か特殊なことをしなければいけないのか?とか散々寄り道をさせられた。

というか手順9と手順10の Signature の値も違うしっ、もっと早く気付けばよかったけど。(ノマド先輩様様が教えてくれた)

Signature の値の公式テスト用サイトが実は存在した。早く言ってヨォォォ。

Signed Request Helper (公式)

困った時はどこが間違っているかを確認するために上記サイトでちまちま確認するのが良いかもしれない。クエリする予定のURLを投げると、パラメーターの順番(未だ良く解っていない)も補正してくれるっぽい。クエリの順番も Amazon 側で Signature の値を検算する際に入れ替えられて計算されるかもしれない(=順番が期待されていないオーダーだと計算エラー、とかもあるかもしれない)。

AWSAccessKeyId=?????
AssociateTag=?????-22
IdType=ISBN
ItemId=??????????
Operation=ItemLookup
ResponseGroup=ItemAttributes%2COffers%2CImages%2CReviews
SearchIndex=Books
Service=AWSECommerceService
Timestamp=2017-01-01T00%3A00%3A00Z

オーダー関係あった・・・。ビッグエンディアン、、かな?

The name-value pairs have been sorted according to byte-order and URL-encoded according to RFC 3986 as required by the Product Advertising API.

だそうでう。
署名(Signature=)がどうとかそのあたりの話は以下にまとまっているっぽい。

Request Authentication (公式)

Associate Tag について以下の記載を見つけて、おやっと思った。えらく甘い書き方してるし。

If you are an existing Product Advertising API customer and your security credentials are linked to an AWS account, you can follow these steps to retrieve your AWS root credentials.

Note

This procedure is only for Product Advertising API customers who use AWS credentials. As a best practice, use IAM user credentials to access the Product Advertising API. You can continue using your root credentials, but root credentials provide unlimited access to your AWS resources. An IAM user has permission to access only the services you specify.

と思って、Associate Tag 部分をすっ飛ばせるかと期待してもきっとダメだろうな・・・

フォローする