AWS SAM、FastAPI、Mangum を使って API 開発をやってみる


# 概要

[AWS SAM、FastAPI、Mangum を使って API 開発をやってみる](https://aws.amazon.com/jp/builders-flash/202304/api-development-sam-fastapi-mangum/)

上記を実施。
チュートリアルはcloud9で行われていたが、次の職場ではVScode上からSSHでリモートのEC2コンテナにexecして開発するとのことなので、dockerで再現してやってみた。
以下やってみてのエトセトラ。

## チュートリアル通りにやって躓いたところ

### sam buildで失敗する

以下で解決

- チュートリアルで示されているDockerfileのimageが取得できるか
  - `docker pull public.ecr.aws/lambda/python:3.9`
- 取得できた場合、そのimageでlocalビルドできるか？
  - `docker build -t test-lambda ./hello_world`
- Buildできる場合、特に依存関係等は複雑に設定をしていないのでDockerのキャッシュ周りが怪しい
  - 全部削除してみる
    - `docker builder prune -a`
- キャッシュに依存しないでもう一度sam buildしてみる
  - `sam build --cached`
  - `sam build --no-cache`

### sam deploy後、エンドポイントを叩くと`{"message": "Internal server error"}%`  となる

どうやらLambdaのコンテナイメージでアーキテクチャを明示しないといけないらしい

[参考](https://qiita.com/mshr0969/items/3b958c2a5d4ca1b9432c)

Macなのでarm64で指定しておく

```template
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    # Lambda関数をDockerで作成
    Properties:
      PackageType: Image
      # コンテナイメージのアーキテクチャを指定しておかないとエラーになるので指定
      Architectures:
        - arm64
```

### `tests/integration/test_api_gateway.py` のpytestが失敗する

cloud9ではなく、localでコンテナ化したためAWS認証情報が足りないのでaws configureする。

**実際は systems manager等から引っ張り出すか、profileにするかする**
**リージョンとスタック名の設定もしておく(スタック名は本来なら環境変数にしておく)**

- `export AWS_SAM_STACK_NAME=buildersflash-aws-sam-app`
- `export AWS_DEFAULT_REGION=ap-northeast-1`

#### TIPS: CLIは後からいれるのは面倒なのであらかじめインストールしておくようにDockerfileに仕込む

```docker
# イメージの設定、Macなのでarm64としておく
FROM --platform=linux/arm64 base as stage-arm64

# CLIとSessionManagerとSAM CLIのインストール
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip" && \
    unzip awscliv2.zip && \
    ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update && \
    rm -rf awscliv2.zip
RUN curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_arm64/session-manager-plugin.deb" -o "session-manager-plugin.deb" && \
  apt-get install -y ./session-manager-plugin.deb && \
    rm -f session-manager-plugin.deb
RUN curl -LO "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-arm64.zip" && \
    unzip aws-sam-cli-linux-arm64.zip -d sam-installation && \
    ./sam-installation/install && \
    rm -rf aws-sam-cli-linux-arm64.zip sam-installation
```

## SAMのローカル実行について

ローカルでのテストはコンテナ外でもできる。
(実際にdeployしたAPIを叩くなら、当然だけどexecして中で叩かないとダメ)

- `sam local start-lambda`
  - 上記を実行した上で別のターミナルで以下を入力してみる

    ```zsh
    aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "[http://127.0.0.1:3001](http://127.0.0.1:3001/)" --payload file://events/event.json --cli-binary-format raw-in-base64-out response.json
    ```

    - `--function-name`  設定した関数名
    - `--endpoint-url`  関数(API)のエンドポイント
    - `--payload`  関数をmockをするためのパラメータが入っているファイルを指定
    - `--cli-binary-format raw-in-base64-out response.json`  出力内容
  - あとは`cat response.json`  で内容を見れる(`rm response.json` で消しておくのも忘れずに)
- `sam local start-api`
  - start-lambdaはLambda関数自体のエミュレータだが、こちらはAPIGatewayのエミュレータ
  - 定義された API エンドポイント（`template.yaml` に記載）をローカルで起動し、それにアクセスし、それを通じてLambda関数をキックする
  - コマンド実行後、`curl -X GET エンドポイント` でAPIを叩いて実行結果を見れる