こんにちは、ゲームソリューショングループのsoraです。
今回は、Lambda(Go)で猫の1日当たりのエネルギー供給量を計算するAPIを作って、API Gatewayでテストしてみたことについて書いていきます。
ちなみに、API Gatewayを使わずともLambda上でテストも可能です。
今回はあえて無駄にAPI Gatewayを使用します。
Lambdaで使用するコード(Go)
Goソースコード
猫の体重と生後何か月かを与えると、猫の1日の食事量(kcal)の計算をしてくれる関数です。
計算式についてはあくまで参考程度でお願いいたします。
LambdaでGoを使用するときは、6行目のGo用のLambdaプログラミングモデルをimportする必要があります。
api.go
package main
import (
"fmt"
// Go用のLambdaプログラミングモデル
"github.com/aws/aws-lambda-go/lambda"
)
type GetData struct {
Weight float32 `json:"Weight"`
Month int `json:"Month"`
}
type ReturnData struct {
Answer string `json:"Answer"`
}
func CatCalAPI(event GetData) (ReturnData, error) {
var per float32 = 30 * event.Weight + 70
switch {
case event.Month <= 4:
var kcal float32 = per * 3.0
return ReturnData{Answer: fmt.Sprintf("%.1f kcal", kcal)},nil
case event.Month <= 6:
kcal := per * 2.5
return ReturnData{Answer: fmt.Sprintf("%.1f kcal", kcal)},nil
case event.Month <= 12:
kcal := per * 2.0
return ReturnData{Answer: fmt.Sprintf("%.1f kcal", kcal)},nil
case event.Month <= 95:
kcal := per * 1.2
return ReturnData{Answer: fmt.Sprintf("%.1f kcal", kcal)},nil
case event.Month > 95 :
kcal := per * 1.1
return ReturnData{Answer: fmt.Sprintf("%.1f kcal", kcal)},nil
default :
return ReturnData{Answer: fmt.Sprintf("error")},nil
}
}
func main() {
lambda.Start(CatCalAPI)
}
作成したGoファイルのビルド
GoファイルをLambdaに持っていく前に、ビルドをする必要があります。
Terraformでlocal-execを使ってビルドコマンドもまとめることもできますが、今回は手動で実施します。
Terraformにまとめたい方は以下ページを参考にしてください。
GolangのLambda関数をTerraformだけでデプロイする
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o api
ビルドが終わったら、apiという名前のファイルができています。
LambdaとAPI Gatewayの作成
Terraformソースコード
AWS側で必要なサービスを作成していきます。
私は最近CDKと仲違いしたため、Terraformを使って作成します。
main.tf
terraform {
#AWSプロバイダーのバージョン指定
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.51.0"
}
}
#tfstateファイルをS3に配置する(配置先のS3は事前に作成済み)
backend s3 {
bucket = "sora-tfstate-bucket"
region = "ap-northeast-1"
key = "tf-test.tfstate"
}
}
#AWSプロバイダーの定義
provider aws {
region = "ap-northeast-1"
}
#Lambda用IAMロールの信頼関係の定義
data aws_iam_policy_document assume_role {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
actions = ["sts:AssumeRole"]
}
}
#Lambda用IAMロールの作成
resource aws_iam_role iam_for_lambda {
name = "CatAPI_Lambda_Role"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
#Lambdaへの配置ファイルのzip化
data archive_file lambda {
type = "zip"
source_file = "../api/api"
output_path = "handler.zip"
}
#Lambdaの作成
resource aws_lambda_function CatAPI_Lambda {
filename = "handler.zip"
function_name = "CatAPI_Lambda"
role = aws_iam_role.iam_for_lambda.arn
handler = "api"
source_code_hash = data.archive_file.lambda.output_base64sha256
runtime = "go1.x"
}
#API Gatewayの作成
##APIの作成
resource aws_api_gateway_rest_api CatAPIGateway {
name = "CatAPIGateway"
endpoint_configuration {
types = ["REGIONAL"]
}
}
##リソースの作成
resource aws_api_gateway_resource CatAPIResource {
rest_api_id = aws_api_gateway_rest_api.CatAPIGateway.id
parent_id = aws_api_gateway_rest_api.CatAPIGateway.root_resource_id
path_part = "resource"
}
##メソッドの作成
resource aws_api_gateway_method CatAPIMethod {
rest_api_id = aws_api_gateway_rest_api.CatAPIGateway.id
resource_id = aws_api_gateway_resource.CatAPIResource.id
http_method = "GET"
authorization = "NONE"
request_parameters = {
"method.request.querystring.Weight" = true
"method.request.querystring.Month" = true
}
}
##リクエスト統合の作成
resource aws_api_gateway_integration CatAPIIntegration {
rest_api_id = aws_api_gateway_rest_api.CatAPIGateway.id
resource_id = aws_api_gateway_resource.CatAPIResource.id
http_method = aws_api_gateway_method.CatAPIMethod.http_method
integration_http_method = "POST"
type = "AWS"
uri = aws_lambda_function.CatAPI_Lambda.invoke_arn
request_templates = {
"application/json" = <<-EOT
{
"Weight": $input.params('Weight'),
"Month": $input.params('Month')
}
EOT
}
}
##レスポンスメソッドの作成
resource aws_api_gateway_method_response CatAPIResponse {
rest_api_id = aws_api_gateway_rest_api.CatAPIGateway.id
resource_id = aws_api_gateway_resource.CatAPIResource.id
http_method = aws_api_gateway_method.CatAPIMethod.http_method
status_code = "200"
response_models = {
"application/json" = "Empty"
}
}
##レスポンス統合の作成
resource aws_api_gateway_integration_response CatAPIResponseIntegration {
rest_api_id = aws_api_gateway_rest_api.CatAPIGateway.id
resource_id = aws_api_gateway_resource.CatAPIResource.id
http_method = aws_api_gateway_method.CatAPIMethod.http_method
status_code = aws_api_gateway_method_response.CatAPIResponse.status_code
}
41行目のarchive_fileで先ほどビルドして生成したファイルをzip化しています。
猫の体重(kg)を指すWeightと猫の生後何か月かを指すMonthの2つの値を与える必要があるため、API Gatewayのメソッドリクエストで必須パラメータとしています。
デプロイ
作成したTerraformのコードを実行して構築します。
CDKであればdeployですが、Terraformはapplyなのは間違えがちです。
terraform init
terraform apply
LambdaとAPI Gatewayを確認すると、正常に構築できていることが確認できます。
API Gatewayでのテスト
構築できたのでAPI Gatewayでテストしていきます。
私の飼っている猫は生後3か月で体重1kgのため、
Month=3&Weight=1
とします。
レスポンス本文のところに、猫の1日の食事量(kcal)が表示されています。
最後に
今回は、Lambda(Go)で猫の1日当たりのエネルギー供給量を計算するAPIを作って、API Gatewayでテストしてみたことを記事にしました。
どなたかの参考になると幸いです。