API GatewayでLambdaと接続したREST APIを作成する(Bedrockの呼び出し結果の取得)

[Supership](https://supership.jp/)の名畑です。2024春アニメ開幕の季節がやってきましたが、[うる星やつらの最終クールのPV](https://www.youtube.com/watch?v=4hMO9mkM7Ac)ですでに涙腺が。

## はじめに

以下2つの過去記事では[Lambda](https://qiita.com/nabata/items/36a642597a92f0ece9d8)を経由して[Bedrock](https://aws.amazon.com/jp/bedrock/)の**Claude 3**を叩きました。

- [LambdaでBedrockのClaude 3を呼び出してみた](https://qiita.com/nabata/items/5bcc3beb76182f626040)
- [BedrockのナレッジベースでRAGを実装し、資料を元にした回答をClaude 3にLambda経由でしてもらった(ベクトルストアはAurora)](https://qiita.com/nabata/items/36a642597a92f0ece9d8)


今回は[API Gateway](https://aws.amazon.com/jp/api-gateway/)と**Lambda**を接続することにより、発行された**URL**を経由して同様の結果を取得するようにしてみます。
**Lambda**をWeb API経由で呼び出すというだけなので、本記事単体として特に目新しい内容はありません。

今は[Lambda 関数 URL](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-urls.html)というものがあるのでこれを直接叩いてもいいのかもしれないですが、せっかくなのでよりさまざまな制御ができそうな**API Gateway**を使ってみます。

> Amazon API Gateway は、あらゆる規模の REST、HTTP、および WebSocket API を作成、公開、維持、モニタリング、およびセキュア化するための AWS のサービスです。API 開発者は、AWS または他のウェブサービス、AWS クラウドに保存されているデータにアクセスする API を作成できます。API Gateway API デベロッパーとして、独自のクライアントアプリケーションで使用するための API を作成できます。または、API をサードパーティーのアプリ開発者に対して使用可能にできます。
> 
> 参考：[Amazon API Gateway とは何ですか? - Amazon API Gateway](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html)

## REST APIの作成する

コンソールで**API Gateway**を開いて「**APIを作成**」をクリックし、次に**REST API**の**構築**をクリックします。

![apigateway-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/db19ff30-4a47-9d25-c28d-d684267edeee.png)

遷移先の画面で「**APIの詳細**」としては**新しいAPI**を選択して、**API名**は**lambda-sample**としました。

「**APIを作成**」をクリックするとAPIが用意されます。

## リソースの作成

次に**API Gateway**の**リソース**のページで「**リソースを作成**」をクリックします。

![apigateway-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/c480cbec-7a78-eeed-5cec-f7d8119af910.png)

**リソース名**は**lambda-sample-resource**としました。

「**リソースを作成**」をクリックします。

## メソッドの作成

次に「**メソッドを作成**」をクリックします。

![apigateway-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/9e07fff8-a42b-dc56-250a-2d3d96d1861c.png)

**メソッドタイプ**は**POST**を選び、**統合タイプ**は**Lambda関数**を選びます。

次に**Lambda関数**として[過去記事](https://qiita.com/nabata/items/5bcc3beb76182f626040)で作成済みのLambdaを示す**ARN**を選びます。

「**メソッドを作成**」をクリックします。

## テスト

ここまでで一回テストをしてみようと思います。

テストはコンソール上で可能です。

![apigateway-4a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/5282a13d-01e9-29cb-9a5c-64775dd7b36f.png)

リクエスト本文に**Lambda**へパスする内容をそのまま書き、**テスト**をクリックします。

今回は下記の内容を**Lambda**に渡しました。

```shell-session
{
  "message": "あなたの会社名を教えてください"
}
```

そうすると結果が表示されます。

![apigatewary-4b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/d74e758f-c6a6-6cc2-6c1d-095715f15288.png)

> "text": "私の会社の名前は株式会社あいうえおほげです。"

API自体は無事に動いていそうです。

## デプロイ

**リソース**のページで「**APIのデプロイ**」をクリックします。

![apigateway-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/bf43b9d0-aed1-d376-0dcc-b9cf21ab289a.png)

**ステージ**として**新しいステージ** を選んで、**ステージ名**は**lambda-sample-stage**としました。

**デプロイ**をクリックします。

これでAPIがデプロイされ、また、URLが発行されます。

**https://{restapi\_id}.execute-api.{region}.amazonaws.com/{stage_name}/**

というフォーマットのものです。

今回の場合は東京リージョンで設定したため

**https://{restapi\_id}.execute-api.ap-northeast-1.amazonaws.com/lambda-sample-stage/**

となります。
**restapi\_id**にはAWSから発行されたIDが入ります。

## 外部から呼び出してみる

ターミナルから**curl**コマンドを使って呼んでみます。
今回は作成済みの**lambda-sample-resource**が呼び出し対象のため、URLの末尾につけています。 **{restapi\_id}** の箇所は各自で置き換えてください。

```shell-session
$ curl https://{restapi_id}.execute-api.ap-northeast-1.amazonaws.com/lambda-sample-stage/lambda-sample-resource -d '{"message": "あなたの会社名を教えてください"}' 
```

コンソールからの呼び出しと同様のレスポンスが確認できました。

## APIキーを用いた制限

ここまでで外部から叩くAPIを作成するという目的は達成されましたが、せっかくなので**APIキー**を用いたアクセス制限も実装してみようと思います。

### 注意

> API キーを、API へのアクセスを制御するための認証または承認に使用しないでください。使用量プランに複数の API がある場合、その使用量プランの 1 つの API に対して有効な API キーを持つユーザーは、その使用量プランのすべての API にアクセスできます。代わりに、API へのアクセスを制御するには、IAM ロール、Lambda オーソライザー、または Amazon Cognito ユーザープールを使用します。
> 
> API Gateway が生成する API キーを使用します。API キーには機密情報を含めないでください。クライアントは通常、ログに記録できるヘッダーで機密情報を送信します。
> 
> 参考：[API キーを使用した使用量プランの作成と使用 - Amazon API Gateway](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-api-usage-plans.html)

### 使用量プランの作成

まず、対象のAPIキーにどれだけの使用を許可するかの設定を行います。

「**使用量プランを作成**」をクリックして、遷移先の画面で入力していきます。

![apigateway-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/94a73b90-1b2e-6d79-4e6c-2f2469ae0dcc.png)

名前は**lambda-sample-plan**としました。

[スロットリング](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-request-throttling.html)として**レート**(クライアントがAPIを呼び出すことができる1秒あたりのリクエスト数)は**1**、バースト(APIに対して同時に実行できるリクエストの数)も**1**としてみました。
**リクエスト**(期間内でユーザーが実行できるリクエストの総数)は1日あたり100としました。

この辺りの数値は用途によって適宜変えてください。

最後に「**使用量プランを作成**」をクリックします。

### APIキーの作成

次に**APIキー**を作成します。

**APIキー**のページで「**APIキーの作成**」をクリックします。

![apigateway-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/889e6096-db83-c95f-d42c-4b8ab8d9ab0b.png)

今回は**lambda-sample-key**という名前にしました。
**保存**を押すとAPIキーが作成されます。

このAPIキーをのちほど呼び出し時に使います。

### APIキーを使用量プランに追加

**使用量プラン**に**APIキー**を追加します。

![apigateway-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/0bf976c6-d2a1-0c31-5ed4-2c9d4f02ba01.png)

作成した**APIキー**のページに行き「**使用量プランに追加**」をクリックします。
作成済みの**使用量プラン**を選んで**保存**を押します。

### 使用量プランとステージを紐付け

![apigateway-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/ec276713-77f3-e19c-2604-f655b0759d5c.png)

**使用量プラン**のページで「**ステージを追加**」をクリックし、紐づける**API**と**ステージ**を選択します。
今回であれば**lambda-sample**と**lambda-sample-stage**となります。

このページで「**メソッドレベルのスロットリング**」も設定可能です。今回は設定せずにおきます。

「**使用量プランに追加**」をクリックします。

### POSTでAPIキーを必須とする

該当のAPIキーが付与されていない場合はAPIリクエストを受け付けないようにしてみます。

![apigateway-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/665352f5-0ae2-711c-f838-9090995c14a1.png)

メソッドリクエストの設定はデフォルトでは「**APIキーは必須です**」が**False**になっているかと思います。

![apigateway-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/2fe0930c-75f9-4413-de26-eb05825c8ad3.png)

**編集**をクリックして「**APIキーは必須です**」にチェックを入れて**保存**をクリックします。

### デプロイとテスト

APIはデプロイしないと変更が反映されないので、デプロイしましょう。

```shell-session
$ curl https://{restapi_id}.execute-api.ap-northeast-1.amazonaws.com/lambda-sample-stage/lambda-sample-resource -d '{"message": "あなたの会社名を教えてください"}' 
{"message":"Forbidden"}
```

先ほどと同じようにcurlを呼んだ場合、**Forbidden**となりました。

では次に、先ほど発行した**APIキー**をヘッダーに付与した上でcurlを呼んでみます。

```shell-session
$ curl https://{restapi_id}.execute-api.ap-northeast-1.amazonaws.com/lambda-sample-stage/lambda-sample-resource -d '{"message": "あなたの会社名を教えてください"}' -H 'X-API-KEY:{発行済みのAPIキーをここに書く}'    
```

この場合は無事にレスポンスが返ってきました。

## 最後に

次はなにをしてみようか。

## 宣伝

[SupershipのQiita Organization](https://qiita.com/organizations/supership-inc)を合わせてご覧いただけますと嬉しいです。他のメンバーの記事も多数あります。

Supershipではプロダクト開発やサービス開発に関わる方を絶賛募集しております。
興味がある方は[Supership株式会社 採用サイト](https://supership.jp/recruit/)よりご確認ください。