then-request モジュールを用いて、Lambdaで HTTPリクエスト を同期処理

# はじめに
Lambdaが同期処理でAPIを叩くために、モジュールを探すと、sync-requestがありましたが、商用では非推奨で、then-requesを推奨されておりました。

`then-request`は、非同期処理ですが、`await`を使えば、同期処理できますので、Lambdaで`then-request`を使い、同期処理でAPIを叩き、結果を返す方法をまとめます。

同期的に WebページやAPIの取得をしたい場合に参考になるかと思います。

# then-requestモジュール

`then-request`モジュールを使用するため、ローカルで`then-request`モジュールをインストールします。
```terminal
$ mkdir nodejs
$ cd nodejs
$ npm init -y
$ ls
package.json

$ npm install then-request

$ touch index.js

$ tree
.nodejs
├── index.js
├── node_modules
├── package-lock.json
└── package.json

$ zip -r nodejs.zip *
```
zip化したnodejs.zipは、Lambda作成後にアップロードする必要があります。
そのため、`index.js`ファイルも作成しました。

# Lambda作成
名前は、適当に記載し、ランタイムは、最新のNode.jsを選択し、他はデフォルトのままにします。
![スクリーンショット 2022-10-14 11.39.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/81fb2e02-7536-d031-c6a6-2bc5420320b8.png)

先程作成したzipファイルをアップロードします。
![スクリーンショット 2022-10-14 11.41.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/05ca48ac-7991-9cad-28c0-6dbf6a4578e5.png)

![スクリーンショット 2022-10-14 12.15.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/5bf75c82-2b99-5c2a-8f86-a4dd1e53f750.png)

リクエスト時のPOSTとGETの２パターン分けて紹介します。
## コード1(POSTの場合)
```index.js
const request = require('then-request');

exports.handler = async (event, context, callback) => {
  const data = {
    title: 'user',
    api_key: 'testest',
  };
  // awaitで同期処理
  const apiResponse = await request('POST', 'https://example.co.jp/', { json: data })
    .getBody('utf8')
    .then(JSON.parse);
  console.log('Received apiResponse:', JSON.stringify(apiResponse, null, 2));
};
```
シンプルなPOSTのリクエストになります。
json形式でPOSTする場合、`{ json: data }`の形で渡します。`.then(JSON.parse);`も必須です。
## コード2(POSTの場合)

```index.js
const request = require('then-request');

exports.handler = async (event, context, callback) => {
  const apiData = [
    {
      api_url: 'https://fuga.com',
      api_key: 'fugafuga',
    },
    {
      api_url: 'https://example.com',
      api_key: 'testest',
    },
  ];

  let userIds = [];

  await Promise.all(
    apiData.map(async (item, index) => {
      const data = {
        title: 'user',
        api_key: item.api_key,
      };
      // awaitで同期処理
      const apiResponse = await request('POST', item.api_url, { json: data })
        .getBody('utf8')
        .then(JSON.parse);

      userIds.push(apiResponse.user_id);
    })
  );
  console.log('Received userIds:', JSON.stringify(userIds, null, 2));
  return userIds;
};
```

mapメソッド 内で async と await を使用する場合、`Promise.all()`を利用する必要があります。

## コード（GETの場合）
```index.js
const request = require('then-request');

exports.handler = async (event, context, callback) => {
  const apiResponse = await request('GET', 'https://example.co.jp/', { timeout: 2000 })
    .getBody('utf8');

  console.log('Received apiResponse:', JSON.stringify(apiResponse, null, 2));
};
```
`{ timeout: 2000 }`は、２秒以内に応答がない場合、タイムアウトになります。

# 参照

https://www.npmjs.com/package/then-request

https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/using-async-await.html

https://ginneko-atelier.com/blogs/entry482/#map%E3%81%A7%E9%85%8D%E5%88%97%E5%87%A6%E7%90%86

https://zenn.dev/ruru/articles/21a4b46abf33f5