はじめに
前回はProduct Advertising APIを使うための諸準備と簡単な動作確認をしました。今回はSpringのRestTempateを使ってJavaからAPIを呼び出し、公式のxsdファイルから作ったItemSearchResponseクラスで受け取ります。
開発環境
- Maven 3.0以上
- JDK 1.8以上
手順
1つずつ説明していきます。
下準備
AmazonのProduct Advertising APIを使うために必要な情報(Associate Tag, Access Key ID, Secret Access Key)は前回の記事を参照してください。まずはAPIを受け取るクラスを作ります。
xsdファイルからJavaプログラムの自動生成
自動生成したプログラムについてはGithubに公開しました。 Amazonはxsdファイルを公開していて、これを使ってProduct Advertising APIに関わるJavaクラスを自動生成します。xsdファイルをダウンロードして、以下のコマンドを実行してください。「xjc」はJDK1.8以上をインストールしていれば標準で入っているはずです。「AWSECommerceService.xsd」はxsdファイルの名前です。
$ xjc AWSECommerceService.xsd
ここで注意事項ですが、日本語のWindows環境で上記を実行すると、自動生成されたプログラムのコメントが日本語になります。・・・が、SJISエンコードなのでUTF8環境では日本語が文字化けします。SJIS日本語コメントはいらぬバグの温床になるので、Linux環境で上記を実行することをおすすめします。一応、Product Advertising APIではプログラムを利用する上で問題は起こりませんでした。 これでProduct Advertising API関連のJavaクラスが整いました。これに公式で用意している「SignedRequestHelper」を組み合わせればAPIのやりとりが簡単にできます。一応、SignedRequestHelperも上記のGithubで公開しています。
Javaから呼び出す、受け取る
Spring-webのRestTemplateを使ってスマートにAPIのやり取りをします。こちらもGithubで実装を公開しています。以下では要所要所を解説します。 まず、SignedRequestHelperを初期化します。「endpoint」はProduct Advertising APIのエンドポイントで、Amazon.co.jpの場合は「webservices.amazon.co.jp」とします。「accesskey_id」は「Access Key ID」を、「secretkey」は「Secret Access Key」をそれぞれ入力します。
SignedRequestsHelper helper = SignedRequestsHelper.getInstance(endpoint, accesskey_id, secretkey);
APIのパラメーターをMapクラスで持ちます。「AssociateTag」は「Associate Tag」を入力します。
Map<String, String> params = new HashMap<String, String>();
params.put("Service", "AWSECommerceService");
params.put("Operation", "ItemSearch");
params.put("AssociateTag", associate_tag);
params.put("SearchIndex", search_index);
params.put("Keywords", keywords);
params.put("ResponseGroup", response_group);
params.put("ItemPage", page.toString());
if (!sort.isEmpty() && !search_index.equals("All"))
params.put("Sort", sort);
「SearchIndex」はいわゆるジャンルになります。必須パラメーターです。指定できるパラメータはこちらにあります。例えば、全体の場合は「All」、DVDやBlu-rayの場合は「DVD」を指定します。 「Keywords」は検索キーワードです。例えば「スーパーナチュラル」と入力します。 「ResponseGroup」はAPIのレスポンスに指定する内容です。指定できる内容はこちらにあります。コンマ区切りで複数指定できます。例えば「Images,ItemAttributes,Offers」を指定しておけばOKでしょう。 「ItemPage」はページ指定番号です。Product Advertising APIは一回のリクエストで10件取得(固定)です。11件目移行は、例えば「ItemPage」に「2」を指定します。「SearchIndex=All」の場合は1~5まで、それ以外の場合は1~10まで指定できます。 「Sort」はソート方法です。指定できるパラメータはこちらにあります。「SearchIndex=All」の場合は指定できませんし、指定するとそもそもエラーが返ってきます。それ以外の場合はSearchIndex次第なのですが、基本的に「price」「-price」「salesrank」「keyword」はどれにもあります。それぞれ「価格の安い順」「価格の高い順」「売れてる順」「キーワード一致順」です。 他にも指定できるパラメータがありますが、基本的には上のものだけである程度のことはできると思います。 次にリクエストURLを生成します。SignedRequestHelperが自動的に暗号化してくれます。
String requestUrl = helper.sign(params);
URL url = new URL(requestUrl);
URI uri = url.toURI();
上記URIを呼び出して、xsdファイルから自動生成したItemSearchResponseクラスで受け取ります。Product Advertising APIは世界中から高頻度で呼ばれているせいか、基本的に503エラーが返ってきます。503エラーは「アクセスしすぎ」というエラーですが、公式にはRateLimitは1秒1回です。1秒1回以下のリクエストでも503エラーが頻発するので、503エラーが返ってきた時は少しディレイを与えることで確実にレスポンスが返ってくるように工夫します。
ItemSearchResponse response = null;
int i=0;
while (i<5) {
try {
response = restTemplate.getForObject(uri, ItemSearchResponse.class);
break;
} catch (RestClientException e) {
LOG.error("RestClientException",e);
response = new ItemSearchResponse();
i++;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
LOG.error("InterruptedException",e);
}
}
ItemSearchResponseクラスで受け取ることで、Product Advertising APIを使いやすくなります。たとえば、APIのレスポンスから商品名と価格を取得するには以下のようにします。
for (Items items: response.getItems()) {
for (Item item: items.getItem()) {
String title = item.getItemAttributes().getTitle();
String price = "N/A";
if (item.getOfferSummary().getLowestNewPrice() != null)
price = item.getOfferSummary().getLowestNewPrice().getFormattedPrice();
}
}
おわりに
AmazonのProduct Advertising APIにはJavaのSDKはありませんが、公式のxsdファイルとSpringのRestTemplateを組み合わせることで非常に使いやすい状態に持っていくことができました。ソースコードも公開しているので参考にしてください。