【AWS】localhost:3000とAPI Gatewayでやりとりするために必要な設定

どうもこんにちは。

今回は、ローカル環境で動かしているアプリケーションとAPI Gatewayでやりとりするための方法をメモとして残しておきたいと思います。

# 環境

今回使用する環境はこちらです。

- ローカル環境
    - Next.js([`Vercel V0`](https://qiita.com/PDC-Kurashinak/items/bc25e63ba406c0e24eef)で作成したアプリケーションを元にしています。)
- AWSサービス
    - API Gateway
    - Lambda（python3.12）

`Vercel V0`については、以下の記事で紹介しています。

https://qiita.com/PDC-Kurashinak/items/bc25e63ba406c0e24eef

# 前提

今回は、ローカル環境のアプリケーションと`Lambda`関数の作成は省略します。

# API GatewayでAPIを作成

## 1. APIの作成

## 1-1. 作成画面へ

API一覧画面の右上にある「APIの作成」ボタンをクリックします。

![スクリーンショット 2024-09-29 22.11.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/f52d8ca6-ce19-d53e-2db3-fb2f07db6804.png)

### 1-2. APIの種類を選択

今回はREST APIを選択します。
REST APIの「構築」ボタンをクリックします。

![スクリーンショット 2024-09-29 22.12.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/a228a4fc-6164-63ab-0bf3-b1315029406f.png)

### 1-3. 必要事項を入力

「新しいAPI」を選択して、API名を入力します。
このAPIはアプリケーション単位で作成した方が良い気がしています。（API内で複数のリソース・メソッドが作成できるため、アプリケーション1つに対してAPIは1つで良いということです。）

![スクリーンショット 2024-09-29 22.13.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/344fccc9-0953-15c5-50b3-4c0c4abfed5b.png)

## 2. リソースを作成

次にリソースを作成します。

### 2-1. 作成画面へ

左上の方に「リソースを作成」ボタンがあるので、クリックします。

![スクリーンショット 2024-09-29 22.17.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/5c07dfc9-2d72-1812-6bc6-876a5ef22940.png)

### 2-2. 必要事項を入力

リソース名には、機能名を入れると良いと思います。
（例：ユーザ管理に関する機能であれば`users`）

また、「CORS (クロスオリジンリソース共有)」の項目にチェックを入れておきます。

![スクリーンショット 2024-09-29 22.18.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/c84a7ab9-7d9b-9d21-3d8b-6613495242c8.png)

### 2-3. リソースができているか確認

作成したリソースが作成されているか確認します。

![スクリーンショット 2024-09-29 22.21.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/29cdccac-a0ba-1ef0-898e-519b163ae871.png)

## 3. メソッドの作成

ここから、`GET`や`POST`などのメソッドを作成します。
また、Lambda関数が作成されていることが前提となっている手順となります。

### 3-1. 作成画面へ

画面の右の方にある「メソッドを作成」をクリックします。

![スクリーンショット 2024-09-29 22.23.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/69c80808-6b1e-bb9e-9bc4-b9862352ec9f.png)

## 3-2. 必要事項を入力

以下のように入力をします。

| 項目名 | 値 |
| --- | --- |
| メソッドタイプ | 以下のいずれかを選択<br>・GET<br>・POST<br>・PUT<br>・PATCH<br>・HEAD<br>・DELETE<br>・ANY |
| 統合タイプ | Lambda関数を選択<br>（VPC内に存在している場合はVPCリンクを選択？） |
| Lambdaプロキシ統合 | ON |
| Lambda関数 | API Gatewayと紐付けるLambda関数のARNを入力 |

![スクリーンショット 2024-09-29 22.25.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/75b2df23-bd42-76ec-c0da-5ae1552fbc31.png)

メソッドが作成されたら、以下のようにリソースの下にメソッドが表示されます。

![スクリーンショット 2024-09-29 22.30.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/93c9a6fe-def9-498c-f5de-a84515cabf77.png)

## 4. 統合リクエストの確認

### 4-1. 統合リクエストの設定画面へ

作成したメソッドの詳細画面に以下のような画面があるので、右上の「統合リクエスト」をクリックします。

![スクリーンショット 2024-09-29 22.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/e97f4ef9-555d-77fc-a51f-047e677b0316.png)

クリックすると画面の下が統合リクエストの画面に切り替わります。

![スクリーンショット 2024-09-29 22.33.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/b4e7907c-8b2d-9f30-72d6-d503fb1cbd3f.png)

Lambdaプロキシ統合が`True`になっていることを確認してください。

## 5. リソースのCORSを有効にする

### 5-1. CORSの設定画面へ遷移

以下の画面のリソース部分（画像だと`/chats`）をクリックします。

![スクリーンショット 2024-09-29 22.30.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/93c9a6fe-def9-498c-f5de-a84515cabf77.png)

画面の右側に「CORSを有効にする」ボタンが表示されているので、クリックします。

![スクリーンショット 2024-09-29 22.42.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/33683efd-8d47-63b0-53a3-c61ebb7b8302.png)


### 5-2. 必要項目にチェック

「ゲートウェイのレスポンス」「Access-Control-Allow-Methods」に全てチェックを入れます。
「Access-Control-Allow-Origin」に`*`が入力されていることを確認します。（ローカル環境での使用であれば、`http://localhost:3000`などと入力してもOKです。`*`はワイルドカードを意味しています。）

![スクリーンショット 2024-09-29 22.39.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/65c97182-516f-5c04-9f93-1b2a895cc670.png)

## 6. APIをデプロイ

これらが全て完了したらAPIをデプロイします。

### 6-1. デプロイ画面へ遷移

「APIをデプロイ」ボタンをクリックします。

![スクリーンショット 2024-09-29 22.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/4b9fc180-efdb-1733-4a0f-12724916a293.png)

### 6-2. ステージを設定

今回は新しいステージを作成します。

「*新しいステージ*」を選択して、ステージ名に「dev」と入力します。

![スクリーンショット 2024-09-29 22.45.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/472ecf5e-515e-5810-5402-9db1b8066950.png)

入力したら「デプロイ」をクリックしましょう。
これでAPIを使用できる準備が整いました。

しかし、これだけではまだ不十分です。
Lambda関数のコード内でレスポンスヘッダーにも設定を入れる必要があります。

## 7. Lambda関数に設定

### 7-1. レスポンスヘッダーを修正

Lambda関数のコードの`return`部分で`headers`を以下のように設定します。

```python
def lambda_handler(event, context):
    # 何かしらの処理
    return {
        'statusCode': 200,
        'headers': {
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Headers': 'Content-Type',
            'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
        },
        'body': json.dumps({
            'result': 'OK'
        })
    }
```

これでローカル環境からAPIを呼び出してLambda関数で処理を実行することができるはずです。

### 7-2. ちゃんとtry...catchはできるようにしておこう

上記のコードでうまくレスポンスが返ってこなかった場合にすぐに原因を特定できるようにはしておきましょう。

コード内では、以下のようにコードを書けばAPIのレスポンスが返ってきた時に異変に気づけます。

```python
def lambda_handler(event, context):
    try:
        # 何かしらの処理
        return {
            'statusCode': 200,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
            },
            'body': json.dumps({
                'result': 'OK'
            })
        }
    except Exception as e:
        print(f"Error: {str(e)}")
        return {
            'statusCode': 500,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
            },
            'body': json.dumps({'message': 'Internal server error'})
        }
```

# まとめ

ローカル環境からAPI Gatewayを通じてAPIを呼び出すためには、以下の2点の設定を忘れないようにしましょう。

- CORSを有効にする
    - `Access-Control-Allow-Origin`を適切に設定
- Lambda関数で`headers`を設定

以上