AWS SAM、FastAPI、Mangum を使って API 開発をやってみる
織田 繁 (株式会社NSD, AWS Community Hero)
こんにちは、AWS Commnity Heroの織田繁 (@OutputSeq) です。
この記事では AWS サーバーレスアプリケーションモデル (SAM)、FastAPI、Mangum を用いた API 開発を紹介が出来ればと思います。4 月ということもあり「これから AWS を学んで行くぞ !」という方々に触っていただければ幸いです。
目次
1. 今回のゴール
1-1. AWS SAM とは
1-2. FastAPI とは
1-3. Mangum とは
2. ハンズオン前提条件
3-1. 開発環境のセットアップ
3-2. SAM を用いた環境の初期構築
3-3. FastAPI、Mangum 対応のソースコードに追加・変更
3-4. build
3-5. ローカル環境での実行・テスト
3-6. deploy
3-7. Amazon API Gateway の実行・テスト
3-8. OpenAPI
4-1. ソースコードの追加・変更
4-2. build
4-3. ローカル環境での実行・テスト
4-4. deploy
4-5. Amazon API Gateway の実行・テスト
4-6. OpenAPI
5. 後始末
5-1. delete
5-2. コンソールからの削除
6. 最後に
ご注意
本記事で紹介する AWS サービスを起動する際には、料金がかかります。builders.flash メールメンバー特典の、クラウドレシピ向けクレジットコードプレゼントの入手をお勧めします。
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 URL、Amazon API Gateway、Application Load Balancer、Lambda@Edge の各イベントを処理するためのアダプタです。
2. ハンズオン前提条件
このハンズオンを始めるにあたって、以下をご確認ください。
- AWS アカウントを持っていること
- AWS に Administorator 権限の IAM ユーザーでログインできていること
- 東京リージョンであること
- Lambda ランタイムは Python3.9 であること
3. ハンズオン手順 (HelloWorld)
3-1. 開発環境のセットアップ
このハンズオンを実施する方々の環境差異を無くすために AWS Cloud9 という統合開発環境を利用します。
AWS Cloud9 が利用できない場合、こちらのブログ をご参考に AWS IDE Toolkits または AWS CloudShell をご利用ください。
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
Y を選択します。
Use the most popular runtime and package type? (Python and zip) [y/N]: Y
Amazon X-Ray は利用しないので、N を選択します。
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: N
Amazon CloudWatch Application Insights は利用しないので、N を選択します。
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 init で sam-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 パイプラインに組み込んでみるなど試していただければ幸いです。
筆者プロフィール
織田 繁
株式会社NSD
AWS samurai / AWS Community Hero
普段は AWS インフラ構築・運用保守・教育を実施しています。育児休暇中で子供を寝かし付けた後にこの記事を書いています。コミュニティ活動としては JAWS-UG 初心者支部 運営メンバーとして楽しんでいます。
Twitter: @OutputSeq / GitHub: @shigeru-oda / zenn.dev: @shigeru_oda
AWS を無料でお試しいただけます