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

2023-04-03
コミュニティ通信

織田 繁 (株式会社NSD, AWS Community Hero)

こんにちは、AWS Commnity Heroの織田繁 (@OutputSeq) です。

この記事では AWS サーバーレスアプリケーションモデル (SAM)、FastAPI、Mangum を用いた API 開発を紹介が出来ればと思います。4 月ということもあり「これから AWS を学んで行くぞ !」という方々に触っていただければ幸いです。


1. 今回のゴール

SAM、FastAPI、Mangum とを組み合わせた簡易的な API 開発を体験いただくことが、当ハンズオン資料のゴールとなります。まずは簡単な HelloWorld メッセージを出力するアプリケーションを作成します。

その後、GET、POST、PUT メソッド機能を追加変更します。

1-1. AWS SAM とは

AWS SAM (サーバーレスアプリケーションモデル、以降 SAM) は、サーバーレスアプリケーション構築用のオープンソースフレームワークです。迅速に記述可能な構文で関数、API、データベース、イベントソースマッピングを表現できます。リソースごとにわずか数行で、任意のアプリケーションを定義して YAML を使用してモデリングできます。

デプロイ中、SAM が SAM 構文を AWS CloudFormation 構文に変換および拡張することで、サーバーレスアプリケーションの構築を高速化することができます。

1-2. FastAPI とは

FastAPI は、Python の標準である型ヒントに基づいて Python 3.6 以降で API を構築するための、モダンで、高速 (高パフォーマンス) な、Web フレームワークです。

主な特徴としては以下があります。

高速 NodeJS や Go 並みのとても高いパフォーマンス (Starlette と Pydantic のおかげです)。最も高速な Python フレームワークの一つです。
高速なコーディング 開発速度を約 200%~300 % 向上させます。
少ないバグ 開発者起因のヒューマンエラーを約 40 % 削減します。
直感的 素晴らしいエディタのサポートやオートコンプリート。 デバッグ時間を削減します。
簡単 簡単に利用、習得できるようにデザインされています。ドキュメントを読む時間を削減します。
短い コードの重複を最小限にしています。各パラメータからの複数の機能。少ないバグ。
堅牢性 自動対話ドキュメントを使用して、本番環境で使用できるコードを取得します。
Standards-base API のオープンスタンダードに基づいており、完全に互換性があります。

1-3. Mangumとは

Mangum は、AWS Lambda で ASGI アプリケーションを実行し、Lambda Function URLAmazon API GatewayApplication Load BalancerLambda@Edge の各イベントを処理するためのアダプタです。


2. ハンズオン前提条件

このハンズオンを始めるにあたって、以下をご確認ください。

  • AWS アカウントを持っていること
  • AWS に Administorator 権限の IAM ユーザーでログインできていること
  • 東京リージョンであること
  • Lambda ランタイムは Python3.9 であること

3. ハンズオン手順 (HelloWorld)

3-1. 開発環境のセットアップ

このハンズオンを実施する方々の環境差異を無くすために AWS Cloud9 という統合開発環境を利用します。

AWS コンソールの検索バーに Cloud9 と入力し、Cloud9 をクリックします。

 画像をクリックすると拡大します

Create environment」ボタンをクリックします。

 画像をクリックすると拡大します

Details 配下の Name に sam-handson、Description にも sam-handson を設定します。

他はデフォルトのまま 「Create」ボタンをクリックします。

 画像をクリックすると拡大します

環境作成に数分待ちます。Successfully created sam-handson. から始まるメッセージ表示が見えたら、「Open」リンクをクリックします。

 画像をクリックすると拡大します

こちらの画面が見えたら成功です、

以降は Cloud9 の画面下にあるターミナルで作業を行います。

 画像をクリックすると拡大します

3-2. SAMを用いた環境の初期構築

Python の最新化

Cloud9 環境に Python はプリインストールされているのですが、Version が古いため Update を行います。この記事を書いている時点では Lambda ランタイム は Python3.9 をサポートしていますので、pyenv を用いて Python3.9 のバージョンへ切り替えを行います。

# git clone
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# bash_profileの編集
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

# bash_profileの読み込み
source ~/.bash_profile

# ライブラリのInstall
sudo yum -y install bzip2-devel xz-devel

# Install 5分程度要します
pyenv install 3.9.13

# Version切り替え
pyenv global 3.9.13

# 最新化後のVersion確認
python --version

AWS CLI の最新化

Cloud9 環境に AWS CLI はプリインストールされているのですが、Version が古いため最新化を行います。

最新の Version を GitHub の AWS CLI version 2 Changelog で確認し、そちらの Version がインストールされていれば成功です。

# インストーラーをDownLoad
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# 解答
unzip awscliv2.zip

# 最新化
sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update

# ゴミ削除
rm -rf aws awscliv2.zip 

# 最新化後のVersion確認
aws --version

AWS SAM CLI の最新化

Cloud9 環境に AWS SAM CLI はプリインストールされているのですが、Version が古いため最新化を行います。

最新の Version は GitHub の AWS SAM CLI release notes で確認し、そちらの Version がインストールされていれば成功です。

# githubよりインストーラーをDownLoad
wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip

# 解答
unzip aws-sam-cli-linux-x86_64.zip -d sam-installation

# 最新化
sudo ./sam-installation/install --update

# ゴミ削除
rm -rf aws-sam-cli-linux-x86_64.zip sam-installation

# 最新化後のVersion確認
sam --version

ハンズオンで必要なパッケージをインストールしておきます。

pip3 install "fastapi[all]"
pip3 install mangum
pip3 install "uvicorn[standard]"
pip3 install boto3
pip3 install pytest
pip3 install requests

テンプレートを使用してサーバーレスアプリケーションの初期化を行います。

cd ~/environment/
sam init

1 を選択します。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

1 を選択します。

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Infrastructure event management
        8 - Serverless Connector Hello World Example
        9 - Multi-step workflow with Connectors
        10 - Lambda EFS example
        11 - Machine Learning
Template: 1

を選択します。

Use the most popular runtime and package type? (Python and zip) [y/N]: Y

Amazon X-Ray は利用しないので、を選択します。

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N

Amazon CloudWatch Application Insights は利用しないので、を選択します。

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N

プロジェクト名は sam-hello-world と入力します。

Project name [sam-app]: sam-hello-world

sam initsam-hello-world という新しいフォルダが作成されていることが確認できます。

hello_world アプリケーションのLambda関数のコード
events  関数を呼び出すために使用する呼び出しイベント
tests  アプリケーションコードの単体テスト
template.yaml アプリケーションのAWSリソースを定義するテンプレート
 画像をクリックすると拡大します

3-3. FastAPI、Mangum 対応のソースコードに追加・変更

本来であれば、sam init で作成されたディレクトリ構造を利用しながら、FastAPI、Mangum を利用するソースコードに変更を加えるのですが、今回は時間短縮のために、事前準備したソースを git clone で用意したいと思います。

buildersflash-aws-sam-app というディレクトリが作成されます

cd ~/environment
git clone https://github.com/shigeru-oda/buildersflash-aws-sam-app.git
cd ~/environment/buildersflash-aws-sam-app/
git checkout version1
 画像をクリックすると拡大します

buildersflash-aws-sam-app ディレクトリでの変更箇所は以下です。

~/environment/buildersflash-aws-sam-app
├── events
│   └── event.json <変更>
├── hello_world
│   ├── app.py <変更>
│   ├── Dockerfile <追加>
│   ├── __init__.py
│   └── requirements.txt <変更>
├── __init__.py
├── README.md
├── template.yaml <変更>
├── tests
│   ├── __init__.py
│   ├── unit
│   │   ├── __init__.py
│   │   └── test_handler.py <変更>
│   ├── integration
│   │   ├── __init__.py
│   │   └── test_api_gateway.py <変更>

各ファイルについての概要は以下の通りです。

ファイル 概要
./template.yaml サーバーレスアプリケーションの内容を定義するファイルです。Globals.Function.Timeout を 3 から 10 に変更し、Lambda がタイムアウトしないように変更しています、詳細な内容は後述します。
./hello_world/app.py アプリケーションの Lambda 関数コードです、詳細な内容は後述します。
./hello_world/requirements.txt build 時にアプリケーションに install するパッケージ一覧です。
./events/event.json Lambda 関数をテスト実行する時に提供するペイロードを記載するファイルです。
./tests/unit/test_handler.py unit テストを実行するファイルです。
./tests/integration/test_api_gateway.py integration テストを実行するファイルです。

./hello_world/app.py の詳細

from fastapi import FastAPI
from mangum import Mangum

app = FastAPI()

@app.get("/hello", status_code=200)
async def root():
  return {"message": "Hello SAM World"}

lambda_handler = Mangum(app)

各 Step は以下のような内容となっています。

from fastapi import FastAPI FastAPI パッケージをインポート
from fastapi import FastAPI Mangum パッケージをインポート
app = FastAPI() FastAPI のインスタンスを作成
@app.get("/hello", status_code=200) パスが /PATH、GET オペレーションを定義するデコレータを作成
async def root(): パスオペレーション関数
return {"message": "Hello SAM World"} コンテンツ返信
lambda_handler = Mangum(app) Mangum でラップし、Lambda ハンドラーとして利用

./hello_world/app.py の詳細

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-handson

  Sample SAM Template for sam-handson

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 10
    MemorySize: 128

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      PackageType: Image
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get
    Metadata:
      DockerTag: python3.9-v1
      DockerContext: ./hello_world
      Dockerfile: Dockerfile

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

各セクションの内容は以下のようになっています。

AWSTemplateFormatVersion テンプレートの機能を識別します。最新のテンプレートの形式バージョンは 2010-09-09 であり、現時点で唯一の有効な値です。
Transform AWS SAM テンプレートファイルに必須セクションです。この宣言は、AWS CloudFormation テンプレートファイルを AWS SAM テンプレートファイルとして識別します。
Description テンプレートに関するコメントを含めることができます。
Globals すべてのサーバーレス関数と API に共通するプロパティを定義することができます。今回は Timeout を 10 秒、MemorySize を 128 MB として設定しています。
Resources スタックに含める Lambda や API Gateway などの AWS リソースを宣言します。今回は Lambda を Docker で作成し、API Gateway と紐付けをしています。
Outputs AWS CloudFormation コンソールで表示する出力値を宣言します。今回は API EndPoint や ARN の出力を設定しています。

3-4. build

サーバーレスアプリケーションの構築を行います。

WARNING メッセージが表示されますが、ハンズオンとしては問題ないのでこのまま進めます。

cd ~/environment/buildersflash-aws-sam-app/
sam build

3-5. ローカル環境での実行・テスト

SAM で実行できる様々な方法の実行・テストを行い、アプリケーションが問題ないことを確認します。

ローカル AWS Lambda 関数を呼び出します。

cd ~/environment/buildersflash-aws-sam-app/
sam local invoke --event ./events/event.json HelloWorldFunction

以下のログが確認できれば成功です。

{"statusCode": 200, "headers": {"content-length": "29", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"message\":\"Hello SAM World\"}", "isBase64Encoded": false}

AWS Lambda をエミュレートするローカルエンドポイントを起動すると、Lambda 関数を呼び出すことができます。

実行 (ターミナル 1)

cd ~/environment/buildersflash-aws-sam-app/
sam local start-lambda

実行 (ターミナル 2)

cd ~/environment/buildersflash-aws-sam-app/
aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --payload file://events/event.json --cli-binary-format raw-in-base64-out response.json
cat response.json
rm response.json

以下のログが確認できれば成功です。

{
    "StatusCode": 200
}
{"statusCode": 200, "headers": {"content-length": "29", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"message\":\"Hello SAM World\"}", "isBase64Encoded": false}

解除 (ターミナル 1)

CTRL+C

サーバーレスアプリケーションをローカルで実行して関数を呼び出します。

実行 (ターミナル 1)

cd ~/environment/buildersflash-aws-sam-app/
sam local start-api

実行 (ターミナル 2)

curl -X GET http://127.0.0.1:3000/hello

以下のログが確認できれば成功です。

{"message":"Hello SAM World"}

解除 (ターミナル 1)

CTRL+C

テストフレームワークを用いて、unit テストを行います。

cd ~/environment/buildersflash-aws-sam-app/
pytest ./tests/unit/test_handler.py -p no:warnings

以下のログが確認できれば成功です。

====================================================================================== test session starts ======================================================================================
platform linux -- Python 3.9.13, pytest-7.2.1, pluggy-1.0.0
rootdir: /home/ec2-user/environment/buildersflash-aws-sam-app
plugins: anyio-3.6.2
collected 1 item                                                                                                                                                                                

tests/unit/test_handler.py .                                                                                                                                                              [100%]

======================================================================================= 1 passed in 0.94s =======================================================================================

3-6. deploy

AWS SAM アプリケーションをデプロイします。

cd ~/environment/buildersflash-aws-sam-app/
sam deploy --guided

ログは省略して選択する項目だけ記載します。

Stack Name [sam-app]: buildersflash-aws-sam-app
AWS Region [ap-northeast-1]: 
Confirm changes before deploy [y/N]: N
Allow SAM CLI IAM role creation [Y/n]: Y
Disable rollback [y/N]: N
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: Y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]: 
SAM configuration environment [default]: 
Create managed ECR repositories for all functions? [Y/n]: Y

3-7. Amazon API Gateway の実行・テスト

ApiEndpoint を CloudFormation の出力結果から取得します。

export AWS_SAM_STACK_NAME=buildersflash-aws-sam-app
API_ENDPOINT=$(aws cloudformation describe-stacks \
  --stack-name ${AWS_SAM_STACK_NAME} \
  --query 'Stacks[*].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' \
  --output text)
echo $API_ENDPOINT

ApiEndpoint に対して /hello のパスで呼び出します。

curl -X GET $API_ENDPOINT/hello

以下のログが確認できれば成功です。

{"message":"Hello SAM World"}

テストフレームワークを用いて、integration テストを行います。

cd ~/environment/buildersflash-aws-sam-app/
export AWS_SAM_STACK_NAME=buildersflash-aws-sam-app
pytest ./tests/integration/test_api_gateway.py -p no:warnings

結果

====================================================================================== test session starts ======================================================================================
platform linux -- Python 3.9.13, pytest-7.2.1, pluggy-1.0.0
rootdir: /home/ec2-user/environment/buildersflash-aws-sam-app
plugins: anyio-3.6.2
collected 1 item                                                                                                                                                                                

tests/integration/test_api_gateway.py .                                                                                                                                                   [100%]

======================================================================================= 1 passed in 0.94s =======================================================================================

3-8. OpenAPI

FastAPI では自動ドキュメント生成を行う機能があります。これにより OpenAPI (旧Swagger) のドキュメントを自動的に生成することができます。

cd ~/environment/buildersflash-aws-sam-app/
uvicorn hello_world.app:app --reload --port 8080

Cloud9 のヘッダーから「Preview」→「Preview Running Application」で画面表示します。

 画像をクリックすると拡大します

Cloud9 上のブラウザで /docs を追加入力し、OpenAPI 画面を表示します。

 画像をクリックすると拡大します

GET」→「Try it out」→「Execute」で OpenAPI 上で API Call をすることができます。

 画像をクリックすると拡大します

4. ハンズオン手順 (GET、Post、Put)

"Hello SAM World" のメッセージを出力できたことを確認できたら、続いては他の http メソッドも作成したいと思います。

4-1. ソースコードの追加・変更

こちらも本来であれば、sam init で作成されたディレクトリ構造を利用しながらソースコードに変更を加えるべきですが、時間短縮のために事前準備したソースを git clone で用意したいと思います。

buildersflash-aws-sam-app ディレクトリの内容が更新されます。

~/environment/buildersflash-aws-sam-app
git checkout version2

buildersflash-aws-sam-app ディレクトリでの変更箇所は以下です。

~/environment/buildersflash-aws-sam-app
├── events
│   └── event.json
│   └── get_item.json <追加>
│   └── post_item.json <追加>
│   └── put_item.json <追加>
├── hello_world
│   ├── app.py
│   ├── Dockerfile
│   ├── __init__.py
│   └── requirements.txt
├── item <追加>
│   ├── app.py <追加>
│   ├── Dockerfile <追加>
│   ├── __init__.py <追加>
│   └── requirements.txt <追加>
├── __init__.py
├── README.md
├── samconfig.toml
├── template.yaml <変更>
├── tests
│   ├── __init__.py
│   ├── unit
│   │   ├── __init__.py
│   │   └── test_handler.py <変更>
│   ├── integration
│   │   ├── __init__.py
│   │   └── test_api_gateway.py <変更>

各ファイルの概要は以下の通りです。

ファイル 概要
./events/get_item.json Lambda 関数をテスト実行する時に提供するペイロードを記載するファイルです。GET メソッド処理の時に利用します。
./events/post_item.json Lambda 関数をテスト実行する時に提供するペイロードを記載するファイルです。POST メソッド処理の時に利用します。
./events/put_item.json  Lambda 関数をテスト実行する時に提供するペイロードを記載するファイルです。PUT メソッド処理の時に利用します。
./item/app.py アプリケーションの Lambda 関数コードです。
./item/Dockerfile Docker で作成するコンテナイメージを管理するためのファイルです。
./item/requirements.txt build 時にアプリケーションに install するパッケージ一覧です。
./template.yaml サーバーレスアプリケーションの内容を定義するファイルです。主な変更点としては、GetItemFunction、PostItemFunction、PutItemFunction が追加されています。
./tests/unit/test_handler.py unit テストを実行するファイルです。主な変更点としては、GetItemFunction、PostItemFunction、PutItemFunction が追加されています。
./tests/integration/test_api_gateway.py integration テストを実行するファイルです。主な変更点としては、GetItemFunction、PostItemFunction、PutItemFunction が追加されています。

4-2. build

サーバーレスアプリケーションの構築を行います。

WARNING メッセージが表示されますが、ハンズオンとしては問題ないのでこのまま進めます。

cd ~/environment/buildersflash-aws-sam-app/
sam build

4-3. ローカル環境での実行・テスト

SAM で実行できる様々な方法の実行・テストを行い、アプリケーションが問題ないことを確認します。

ローカル AWS Lambda 関数を呼び出します。

実行 (Get)

cd ~/environment/buildersflash-aws-sam-app/
sam local invoke --event ./events/get_item.json GetItemFunction

以下のログが確認できれば成功です。

{"statusCode": 200, "headers": {"content-length": "77", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"id\":\"ABC\",\"name\":\"get_item+ABC\",\"description\":\"get_item+ABC\",\"price\":100.0}", "isBase64Encoded": false}

実行(Post)

cd ~/environment/buildersflash-aws-sam-app/
sam local invoke --event ./events/post_item.json PostItemFunction

以下のログが確認できれば成功です。

{"statusCode": 201, "headers": {"content-length": "104", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"id\":\"56b4acad-0f6b-43e6-879d-128c43957752\",\"name\":\"post_item\",\"description\":\"post_item\",\"price\":200.0}", "isBase64Encoded": false}

実行 (Put)

cd ~/environment/buildersflash-aws-sam-app/
sam local invoke --event ./events/put_item.json PutItemFunction

以下のログが確認できれば成功です。

{"statusCode": 201, "headers": {"content-length": "71", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"id\":\"9\",\"name\":\"put_item+9\",\"description\":\"put_item+9\",\"price\":300.0}", "isBase64Encoded": false}

AWS Lambda をエミュレートするローカルエンドポイントを起動し、Lambda 関数を呼び出すことができます。

実行 (ターミナル 1)

cd ~/environment/buildersflash-aws-sam-app/
sam local start-lambda

実行 (ターミナル 2 Get)

cd ~/environment/buildersflash-aws-sam-app/
aws lambda invoke --function-name "GetItemFunction" --endpoint-url "http://127.0.0.1:3001" --payload file://events/get_item.json --cli-binary-format raw-in-base64-out response.json
cat response.json
rm response.json

以下のログが確認できれば成功です。

{
    "StatusCode": 200
}
{"statusCode": 200, "headers": {"content-length": "77", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"id\":\"ABC\",\"name\":\"get_item+ABC\",\"description\":\"get_item+ABC\",\"price\":100.0}", "isBase64Encoded": false}

実行 (ターミナル 2 Post)

cd ~/environment/buildersflash-aws-sam-app/
aws lambda invoke --function-name "PostItemFunction" --endpoint-url "http://127.0.0.1:3001" --payload file://events/post_item.json --cli-binary-format raw-in-base64-out response.json
cat response.json
rm response.json

以下のログが確認できれば成功です。

{
    "StatusCode": 200
}
{"statusCode": 201, "headers": {"content-length": "104", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"id\":\"1e97efc5-f5f1-4e7e-8e36-09cf63a7d2ad\",\"name\":\"post_item\",\"description\":\"post_item\",\"price\":200.0}", "isBase64Encoded": false}

実行 (ターミナル 2 Put)

cd ~/environment/buildersflash-aws-sam-app/
aws lambda invoke --function-name "PutItemFunction" --endpoint-url "http://127.0.0.1:3001" --payload file://events/put_item.json --cli-binary-format raw-in-base64-out response.json
cat response.json
rm response.json

以下のログが確認できれば成功です。

{
    "StatusCode": 200
}
{"statusCode": 201, "headers": {"content-length": "71", "content-type": "application/json"}, "multiValueHeaders": {}, "body": "{\"id\":\"9\",\"name\":\"put_item+9\",\"description\":\"put_item+9\",\"price\":300.0}", "isBase64Encoded": false}

解除 (ターミナル 1)

CTRL+C

サーバーレスアプリケーションをローカルで実行して関数を呼び出します。

実行 (ターミナル 1 Get)

cd ~/environment/buildersflash-aws-sam-app/
sam local start-api

実行 (ターミナル 2 Get)

curl -X GET http://127.0.0.1:3000/item?id=ABC

以下のログが確認できれば成功です。

{"id":"ABC","name":"get_item+ABC","description":"get_item+ABC","price":100.0}

実行 (ターミナル 2 Post)

curl -X POST -H "Content-Type: application/json" http://127.0.0.1:3000/item -d '{"name": "post_item","description":"post_item","price":200.0}'

以下のログが確認できれば成功です。

{"id":"63efad53-ade9-47b1-bc17-6ac7526f69db","name":"post_item","description":"post_item","price":200.0}

実行 (ターミナル 2 Put)

curl -X PUT http://127.0.0.1:3000/item/9

以下のログが確認できれば成功です。

{"id":"9","name":"put_item+9","description":"put_item+9","price":300.0}

 解除 (ターミナル 1)

CTRL+C

テストフレームワークを用いて、unit テストを行います。

cd ~/environment/buildersflash-aws-sam-app/
pytest ./tests/unit/test_handler.py -p no:warnings

以下のログが確認できれば成功です。

====================================================================================== test session starts ======================================================================================
platform linux -- Python 3.9.13, pytest-7.2.1, pluggy-1.0.0
rootdir: /home/ec2-user/environment/buildersflash-aws-sam-app
plugins: anyio-3.6.2
collected 4 items                                                                                                                                                                               

tests/unit/test_handler.py ....                                                                                                                                                           [100%]

======================================================================================= 4 passed in 0.73s =======================================================================================

4-4. deploy

AWS SAM アプリケーションをデプロイします。

cd ~/environment/buildersflash-aws-sam-app/
sam deploy --guided

ログは省略して選択する項目だけ記載します。

Stack Name [buildersflash-aws-sam-app]: 
AWS Region [ap-northeast-1]: 
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: N
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: Y
GetItemFunction may not have authorization defined, Is this okay? [y/N]: Y
PostItemFunction may not have authorization defined, Is this okay? [y/N]: Y
PutItemFunction may not have authorization defined, Is this okay? [y/N]: Y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]: 
SAM configuration environment [default]: 
Create managed ECR repositories for the 3 functions without? [Y/n]: Y

4-5. Amazon API Gateway の実行・テスト

ApiEndpoint を CloudFormation の出力結果から取得します。

export AWS_SAM_STACK_NAME=buildersflash-aws-sam-app
API_ENDPOINT=$(aws cloudformation describe-stacks \
  --stack-name ${AWS_SAM_STACK_NAME} \
  --query 'Stacks[*].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' \
  --output text)
echo $API_ENDPOINT

実行 (Get)

curl -X GET $API_ENDPOINT/item?id=ABC

以下のログが確認できれば成功です。

{"id":"ABC","name":"get_item+ABC","description":"get_item+ABC","price":100.0}

実行 (Post)

curl -X POST -H "Content-Type: application/json" $API_ENDPOINT/item -d '{"name": "post_item","description":"post_item","price":200.0}'

以下のログが確認できれば成功です。

{"id":"2a29a6aa-0377-472c-a2c5-e57e4db9fe6f","name":"post_item","description":"post_item","price":200.0}

実行 (Put)

curl -X PUT $API_ENDPOINT/item/9

以下のログが確認できれば成功です。

{"id":"9","name":"put_item+9","description":"put_item+9","price":300.0}

テストフレームワークを用いて、integration テストを行います。

cd ~/environment/buildersflash-aws-sam-app/
export AWS_SAM_STACK_NAME=buildersflash-aws-sam-app
pytest ./tests/integration/test_api_gateway.py -p no:warnings

以下のログが確認できれば成功です。

====================================================================================== test session starts ======================================================================================
platform linux -- Python 3.9.13, pytest-7.2.1, pluggy-1.0.0
rootdir: /home/ec2-user/environment/buildersflash-aws-sam-app
plugins: anyio-3.6.2
collected 4 items                                                                                                                                                                               

tests/integration/test_api_gateway.py ....                                                                                                                                                [100%]

======================================================================================= 4 passed in 2.00s =======================================================================================

4-6. OpenAPI

自動ドキュメント生成を行う機能を確認します

cd ~/environment/buildersflash-aws-sam-app/
uvicorn item.app:app --reload --port 8080

Cloud9 のヘッダーから「Preview」→「Preview Running Application」 の順に画面表示します。

 画像をクリックすると拡大します

Cloud9  上のブラウザで /docs を追加入力し、OpenAPI 画面を表示します。

 画像をクリックすると拡大します

GET / POST / PUT -> Try it out を開き、「Parameters」や「Request body」を設定したのち、「Execute」で OpenAPI 上で API Call をすることができます。

GET

 画像をクリックすると拡大します

POST

 画像をクリックすると拡大します

PUT

 画像をクリックすると拡大します

5. 後始末

5-1. delete

cd ~/environment/buildersflash-aws-sam-app/
sam delete

削除確認をされますので Y を選択します。

5-2. コンソールからの削除

CloudWatch → ロググループ

以下のロググループを削除します、${xxx} は可変の ID となります。

  • /aws/lambda/buildersflash-aws-sam-app-GetItemFunction-${xxx}
  • /aws/lambda/buildersflash-aws-sam-app-HelloWorldFunction-${xxx}
  • /aws/lambda/buildersflash-aws-sam-app-PostItemFunction-${xxx}
  • /aws/lambda/buildersflash-aws-sam-app-PutItemFunction-${xxx}

Cloud9 -> Environments

以下の環境を削除します。

  • sam-handson

6. 最後に

FastAPI、Mangum を使ってので API 開発をハンズオン形式で体験いただきました。ドキュメントを別で作成不要であったり、アプリケーションの書き方が直感的になっていることがお分かりいただけましたでしょうか。

もしも SAM にすでに慣れている方は sam pipeline で CI/CD パイプラインに組み込んでみるなど試していただければ幸いです。


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

織田 繁
株式会社NSD
AWS samurai / AWS Community Hero

普段は AWS インフラ構築・運用保守・教育を実施しています。育児休暇中で子供を寝かし付けた後にこの記事を書いています。コミュニティ活動としては JAWS-UG 初心者支部 運営メンバーとして楽しんでいます。

Twitter: @OutputSeq / GitHub: @shigeru-oda / zenn.dev: @shigeru_oda

さらに最新記事・デベロッパー向けイベントを検索

下記の項目で絞り込む
1

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する