Amazonが SP-APIを発表しましたが、連日以下のようなエラーに悩まされていませんか? 自分も同じような壁に悩まされたのでメモします。
{
"errors": [
{
"message": "Access to requested resource is denied.",
"code": "Unauthorized",
"details": ""
}
]
}
最初は以下のライブラリを試したのですが、どれを使っても認証エラーなので自分で書くことにしました。
- PYTHON-AMAZON-SP-API - https://sp-api-docs.saleweaver.com/
- Ruby Muffin - 発展途上
- Ruby amz_sp_api - 内部でlibcurlを呼ぶため、windowsでは不向き
アカウントを作成し、postmanで動作確認
神のようなドキュメントがあるので、以下の手順で環境を作ります。
- https://zats-firm.com/2021/09/07/amazon-mws-%e3%81%8b%e3%82%89-sp-api-%e3%81%b8%e3%81%ae%e7%a7%bb%e8%a1%8c-%e6%ba%96%e5%82%99%e7%b7%a8/
- https://zats-firm.com/2021/09/08/amazon-mws-%e3%81%8b%e3%82%89-sp-api-%e3%81%b8%e3%81%ae%e7%a7%bb%e8%a1%8c-postman%e3%81%ab%e3%82%88%e3%82%8b%e3%83%86%e3%82%b9%e3%83%88%e6%8e%a5%e7%b6%9a%e7%b7%a8/
postmanを使った、スクラッチパッドでの動作確認は必須です。時間をドブに捨てないためにも、必ずpostmanで動作確認しましょう。
postman でアクセストークンを取得しているところ
「アクセストークンを取得」がダメなら何をやってもダメです。
時間をドブに捨てないために、postmanでアクセストークンが取得できることを検証しましょう。
トークンを元に、ASINから商品名を得るところ
HTTPの何処に、何を入れるのか?
エラーになった場合、入れる場所が3か所あるので、そこを間違っておりませんか?
この場所に | これを入れる |
---|---|
params (別名 QUERY_STRING) |
GETなAPIでつかうやつ |
HTTP request header | x-amz-access-token: Atzr●●●●●● Content-Type : application/json |
body (別名 POST DATA) | これはJSON textになっている必要がある |
あのパラメータはどこにあるの?
refresh_token は、Amazonデベロッパーセントラルにあります。
client_id / client_secret は、デベロッパーセントラルで、各アプリの「LWA認証情報を表示」ボタンから見れます。
aws_access_key_id / aws_secret_access_key は、AWS IAMから参照します。
Rubyでsp-apiを叩いてみる
ASINを指定すると、商品のタイトルを取得する初歩のAPIで実験してみます。
ヘッダに認証サインする箇所がものすごく面倒なので、公式のAWS SDKを使っています。
gem install aws-sigv4
require "aws-sigv4"
require "json"
require "faraday"
require "faraday_json"
#認証データ
CREDENTIALS = {
# 以下の情報はデベロッパーセントラルから取得します
refresh_token: "Atzr|IwE●●●●●●●●●●●●●●●●●●●●●●●●●●●●●Wo",
client_id: "amzn1●●●●●●●●●●●●●●●●●●●●●●●●●●●●●c1",
client_secret: "amzn1.●●●●●●●●●●●●●●●●●●●●●●●●●●●●●3b",
# 以下の情報はIAM画面から取得します
aws_access_key_id: "AKI●●●●●●●●●●●●●●●●●●●●●●●●●●●●●73",
aws_secret_access_key: "0EOE●●●●●●●●●●●●●●●●●●●●●●●●●●●●●Ii",
}
##---------------
# 認証トークンを設定する
def login_with_amazon(cred)
data = {
:grant_type => "refresh_token",
:refresh_token => cred[ :refresh_token ],
:client_id => cred[ :client_id ],
:client_secret => cred[ :client_secret ] }
conn = Faraday.new("https://api.amazon.com")
conn.response :json
res = conn.post("/auth/o2/token", data).body
return res["access_token"]
end
#
# ASINを指定すると商品のタイトルを得る Catalog Items API v2020-12-01
# @see https://developer-docs.amazon.com/sp-api/docs/catalog-items-api-v2020-12-01-reference
#
def catalogitem(cred, token, asin)
signer = Aws::Sigv4::Signer.new(
service: 'execute-api',
region: 'us-west-2',
access_key_id: cred[:aws_access_key_id],
secret_access_key: cred[:aws_secret_access_key]
)
url = "https://sellingpartnerapi-fe.amazon.com/catalog/2020-12-01/items/#{asin}?marketplaceIds=A1VC38T7YXB528"
signature = signer.sign_request(
http_method: 'GET',
url: url,
headers: {
"host" => "sellingpartnerapi-fe.amazon.com",
'User-Agent' => 'ruby/sp-api',
"x-amz-access-token" => token,
"x-amz-date" => Time.now.getutc.xmlschema.tr('-:',"")
},
)
pp sig_headers = signature.headers
sig_headers["x-amz-access-token"] = token
conn = Faraday.new()
conn.headers = sig_headers
res = conn.get(url).body
return JSON.parse(res)
end
token = login_with_amazon(CREDENTIALS)
pp catalogitem(CREDENTIALS, token, "4000801317") # 4000801317 は広辞苑のASIN
この例では広辞苑のASINを指定していて、以下のような結果が取得できます
{"asin"=>"4000801317", "summaries"=>[{"marketplaceId"=>"A1VC38T7YXB528", "browseNode"=>"500272", "itemName"=>"広辞苑 第七版(普通版)", "manufacturer"=>"岩波書店"}]}
おしまい。