Node.jsでAmazon SP-APIをリクエストする方法：初心者奮闘記

<H1>記事の概要</h1>
Node.jsでAmazonSP-APIのデータをリクエストして、取得できる用にするまでの手順を記載。
私が設定時に手こずった点などを共有できればと思います。

<H1>私のスペック</h1>
Amazonでの物販事業を運営している個人事業主で、プログラミングを学習し始めて約500時間の初心者です。
自分のビジネスで使うツールを自分で開発したく学習を始めました。<br>


当記事執筆時点ではRecursionという学習サイトでコンピューターサイエンスの基礎を学んでおり、何らかのアプリケーションを自分で開発した経験はありません。

ターミナルコマンドも実践しながら覚えている段階、モジュール、パッケージ、ライブラリって何？とChatGPTに聞いているそんなレベル感の人間が書いています。<br>
(用語の間違った使い方や理解があればご指摘いただけると嬉しいです)

<H1>やりたいこと</h1>

北米Amazonの売上、在庫情報、注文情報をAmazonのSP-APIを使って取得し、Googleスプレッドシートに反映されるようにしたい。

<H1>なぜNode.jsなのか？</h1>

RecursionでJavaScriptを使って学習していたため、辛うじて基本的なコードが理解できるため。<br>
また、SP-APIを取得するためのnpmパッケージが用意されており、参考記事もあったため比較的簡単に取得できると考えたから。


<H1>始める前に準備しておくこと</h1>
SP-APIをリクエストするには以下の合計6つのクレデンシャル情報が必要となります。それぞれ、北米Amazonのセラー登録をしてセラーセントラルにログインできること、AWSアカウントがあることが前提となります。

</br>

1. SELLING_PARTNER_APP_CLIENT_ID
2. SELLING_PARTNER_APP_CLIENT_SECRET
3. REFRESH_TOKEN
4. AWS_ACCESS_KEY_ID
5. AWS_SECRET_ACCESS_KEY
6. AWS_SELLING_PARTNER_ROLE

1~3はアマゾンのセラーセントラルから、4~6はAWSから取得します。まずは4~6の取得方法について説明します。


<H1>準備1:AWSからクレデンシャル情報取得</h1>

下記のドキュメントの手順に従って、AWSアカウント、IAMユーザー、IAMポリシー、IAMロールの作成をします。
Step6はオプションなので、Step5までで大丈夫です。

https://developer-docs.amazon.com/sp-api/docs/creating-and-configuring-iam-policies-and-entities

IAMユーザーを登録すると、

4番のAWS_ACCESS_KEY_ID
5番のAWS_SECRET_ACCESS_KEY

が発行されるので、控えておく。

また、IAMユーザーを発行すると6番のAWS_SELLING_PARTNER_ROLEが発行されます。(arn:aws:iam::~から始まる英数字です。)

<H1>準備2:Amazonセラーセントラルから開発者登録</h1>
下記ドキュメントの手順に沿って登録

https://developer-docs.amazon.com/sp-api/docs/registering-as-a-developer

今回僕の場合は自身がセラーで自社内で使うツールを開発したかったため、「To register as a private developer for private seller applications」の手順に沿って登録しました。

日本語メニューだと、左側のメニューの
「アプリとサービス」→「アプリの開発」で、デベロッパーセントラルが表示されると思います。

ここで、「新しいアプリクライアントを追加」を押して、開発するアプリを登録してください。

登録の詳しい方法はこちらのブログの「3.アプリクライアントの追加」からがわかりやすく参考になります。

https://www.greenwich.co.jp/blog-archives/p/26120#:~:text=%E3%81%A6%E3%81%84%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82-,3.%20%E3%82%A2%E3%83%97%E3%83%AA%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%81%AE%E8%BF%BD%E5%8A%A0,-%E3%82%A2%E3%83%9E%E3%82%BE%E3%83%B3%E3%82%BB%E3%83%A9%E3%83%BC

ここまでを終えると、1~3番の情報も取得できているはずです。

これからようやくAPIをリクエストする段階に入ります。

<H1>npmからamazon-sp-apiパッケージをインストール</h1>

ターミナルでamazon-sp-apiという非公式のパッケージをダウンロードします。ターミナルから下記のコマンドでインストール可能です。

```
npm install amazon-sp-api
````

あとはAPIの扱いに慣れている方であれば、下記のドキュメントを見ながらクレデンシャル情報を渡してAPIをリクエストすれば問題なくできるのではないかと思います。

https://www.npmjs.com/package/amazon-sp-api#config-params


私はAPIリクエスト初体験で知らないことがたくさんだったため、下記に復習と備忘録を兼ねて、ここからの手順をさらに詳しく記載していきます。

<H1>APIリクエスト用のjsファイルを作成</h1>

任意の名前で新しくjsファイルを作成して、下記サンプルコードをペーストしてください。
その後、

1. クレデンシャル情報を各項目に貼付
1. region情報をセラーアカウントが登録されているマーケットに合わせて変更(北米-> na, ヨーロッパ->eu,日本を含む極東 -> fe)





``` javaScript:requestAmazonSP-API
const SellingPartnerAPI = require('amazon-sp-api');


(async() => {
    try {
      let sellingPartner = new SellingPartnerAPI({
        region:'na', // ここ重要！！ ("eu", "na" or "fe")
        refresh_token:'3番のREFRESH_TOKENを貼付', // The refresh token of your app user
        credentials:{
            SELLING_PARTNER_APP_CLIENT_ID: '1番のSELLING_PARTNER_APP_CLIENT_IDを貼付
',
            SELLING_PARTNER_APP_CLIENT_SECRET: '2番のSELLING_PARTNER_APP_CLIENT_SECRETを貼付
',
            AWS_ACCESS_KEY_ID: '4番のAWS_ACCESS_KEY_IDを貼付',
            AWS_SECRET_ACCESS_KEY: '５番のAWS_SECRET_ACCESS_KEYを貼付
',
            AWS_SELLING_PARTNER_ROLE: '6番のAWS_SELLING_PARTNER_ROLEを貼付'
          }
      });
      let res = await sellingPartner.callAPI({
        operation:'getMarketplaceParticipations',
        endpoint:'sellers'
      });
      console.log(res);
    } catch(e){
      console.log(e);
    }

    
  })(); 
```

ここではテスト用として、

getMarketplaceParticipations

というセラーが参加しているマーケットプレイス情報を取得するリクエストをしています。

あとはこのjsファイルを実行して、コンソールにリクエストした情報が表示されていれば成功です。


最後に僕が取得の際に遭遇したエラーを共有したいと思います。


<H1>APIリクエストエラー集</h1>

### クレデンシャル情報の不足
```
CustomError: Could not find the following credentials in config object: AWS_SELLING_PARTNER_SECRET_ACCESS_KEY or AWS_SECRET_ACCESS_KEY...
```

そもそも最初にどうやってクレデンシャル情報を渡すべきが分からないときに遭遇しました。 in config object:~の後に続いているキーの項目が足りていない項目です。

### 6番AWS_SELLING_PARTNER_ROLEにSTSポリシーがアタッチされていない

```
CustomError: User: CustomError: User: arn:aws:iam::~~ is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::~~~
```
準備2の手順の際に、IAMロールにSTSポリシーをアタッチしますが、今回クレデンシャル情報として渡したユーザー情報にAPIリクエストをするためのSTSポリシーがアタッチされていないことが原因です。

再度、6番AWS_SELLING_PARTNER_ROLEのユーザーにSTSポリシーが正しくアタッチされているかを確認すればOKです。

自分の場合、STSポリシーない別ユーザーの情報を入れていたためエラーになりました。

### リクエスト先のリージョンが違うorその他設定ミス

```
CustomError: Access to requested resource is denied.
```

これが一番ハマってしまいました...
私の場合は、リクエスト先のリージョンが異なっていたことが原因でした。

私のアマゾンセラーアカウントは北米アマゾンで、下記部分のコードを region:`na`としなければならないところを、region:'eu'としており、ヨーロッパのリージョンにリクエストしていました。

```javascript
region:'na', // ここが重要！！ ("eu", "na" or "fe")
```

npmのドキュメントからコピペしたコードが'eu'になっており、そこに気づかずずっとIAMユーザーやSTSの設定の確認をしていました...

ちなみに、このエラーについてChatGPTに聞いたら下記の答えが返ってきましたので、regionを正しく設定してもエラーが起こるときは参考にしてみてください。


>"Access to requested resource is denied."というエラーメッセージは、要求されたリソースに対するアクセスが拒否されたことを示しています。これは通常、以下のいずれかの理由によるものです：

>1. 認証情報が無効または不適切です：指定した認証情報（AWS IAMユーザーID、シークレットキー、Selling PartnerアプリのクライアントIDとシークレット）が無効か、誤って設定されている可能性があります。これらの値が正確であることを再確認してください。
>2. 承認問題：IAMユーザーまたはSelling Partnerアプリケーションが要求された操作を実行するための適切な権限を持っていない可能性があります。IAMポリシーとSelling Partnerアプリケーションの権限を確認し、必要なアクセス許可が与えられていることを確認してください。
>3. AWSのSelling Partner APIがまだアクティベーションされていない：Amazon Seller Centralでアプリケーションを正常に設定し、承認されたことを確認してください。



<H1>感想</h1>

初めて実践でAPIを取得してみましたが、取得をするまでにこんなに苦労をするとは思っていませんでした。

英語の資料を読んだり、他の方のブログやYoutubeを参考に情報を集めてトライアンドエラーを繰り返し、巷でエンジニアは検索力が非常に大切といわれている理由がわかったような気がします。

大変でしたが、初めてAPIリクエストが成功したのはものすごく嬉しかったです。

ここからやっとツールを作れるようになったので、これからが楽しみです！


<H1>学んだこと＋疑問メモ</h1>


-  APIをリクエストするにはクレデンシャル情報というものが必要。クレデンシャル情報の渡し方をChatGPTに聞いたら下記のような返答。

>1. SellingPartnerクラスのコンストラクタ経由で明示的に設定された情報
>2. ファイルから読み込んだ情報
>3. 環境変数から読み込んだ情報

>ただし、このファイル自体にクレデンシャル情報を直接書き込むべきではありません。その代わりに、このファイルが提供する方法を使用して情報を提供するべきです。上記の3つの方法のいずれかを使用して認証情報を提供できます。

つまり今回の場合に置き換えると
1. APIをリクエストするjsファイルに含める方法
1. require('amazon-sp-spi')で読み込んでいるモジュールそのものの該当の値を書き換える？
1. ターミナルからexportコマンドを使って環境変数を設定する

の3つの方法がある。1の方法が一般的である。
以上の解釈はあってるか疑問。