はじめに
こちらの記事はGoとAPI Gateway + Lambda + DynamoDBでサーバレスなAPIを作る記事となっています。
前回の記事の続きとなっているため、一部手順を省略しています。
環境
MacBook Air M1
開発言語 Go
手順
Lambda関数の作成
一から作成のままランタイムをGo.1.x
アーキテクチャをx86_64
にして関数の作成をします。
必要なパッケージのインストール
go get -u github.com/aws/aws-sdk-go
go get -u github.com/aws/aws-lambda-go
ソースコード
一部抜粋
package main
import (
"context"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func HandleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
req, err := parseRequest(request.Body)
if err != nil {
return errorResponse(err, 500)
}
if err := checkAmazonURL(req.URL); err != nil {
return errorResponse(err, 500)
}
db, err := newDynamoDB()
if err != nil {
return errorResponse(err, 500)
}
if err := db.putAmazonURL(req.URL); err != nil {
return errorResponse(err, 500)
}
return events.APIGatewayProxyResponse{
Body: "Success",
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(HandleRequest)
}
package main
import (
"encoding/json"
"fmt"
"math/rand"
"regexp"
"strconv"
"strings"
"time"
"github.com/aws/aws-lambda-go/events"
)
type Request struct {
URL string `json:"url"`
}
func getRandID() string {
rand.Seed(time.Now().UnixNano())
return strconv.Itoa(rand.Intn(100))
}
func getEpochTime() string {
return strconv.FormatInt(time.Now().Unix(), 10)
}
func parseRequest(inputs string) (*Request, error) {
var req Request
err := json.NewDecoder(strings.NewReader(inputs)).Decode(&req)
if err != nil {
return nil, fmt.Errorf("cannot decode body: %v: %v", err, inputs)
}
return &req, nil
}
func checkAmazonURL(url string) error {
isAmazpnURL, err := regexp.MatchString(`^http(s)?://(www.)?amazon.(co.)?jp[\w!\?/\+\-_~=;\.,\*&@#\$%\(\)'\[\]]*`, url)
if err != nil {
return err
}
if !isAmazpnURL {
return fmt.Errorf("this is not amazon url: %v", url)
}
return nil
}
func errorResponse(err error, statusCode int) (events.APIGatewayProxyResponse, error) {
return events.APIGatewayProxyResponse{
Body: err.Error(),
StatusCode: statusCode,
}, err
}
package main
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
)
type db struct {
ddb *dynamodb.DynamoDB
}
func newDynamoDB() (*db, error) {
sess, err := session.NewSession()
if err != nil {
return nil, err
}
return &db{ddb: dynamodb.New(sess)}, nil
}
func (db *db) putAmazonURL(url string) error {
input := &dynamodb.PutItemInput{
TableName: aws.String("table"),
Item: map[string]*dynamodb.AttributeValue{
"id": {
N: aws.String(getRandID()),
},
"time": {
N: aws.String(getEpochTime()),
},
"url": {
S: aws.String(url),
},
},
}
if _, err := db.ddb.PutItem(input); err != nil {
return err
}
return nil
}
コンパイルしてZIPにする
M1 Macを使っているため、GOARCH=amd64 GOOS=linux
の指定しています。
GOARCH=amd64 GOOS=linux go build -o handler *.go
実行ファイルをzipに圧縮します。
zip function.zip handler
zipのアップロードとランタイム設定変更
コードソースからアップロード元
zipファイル
を選択してアップロードします。
ハンドラの名前を初期のhello
からhandler
に変更します。
DynamoDBの作成とLambdaに実行ロール追加
設定からロール名
ロールの許可ポリシー
までいったら、
ポリシーの編集
を選択してビジュアルエディタでDynamoDB
PutItem
のアクションを追加します。
DynamoDBのテーブルを作成
パーティションキーとソートキーが数値となっている点に注意してください!
Lambda + DynamoDBの連携をテスト
テストのイベント作成して、テンプレートからapigateway-aws-proxy
を選択してイベント JSONのbodyを変更します。
"body": "{\"url\": \"https://www.amazon.co.jp\"}",
API Gatewayとの連携
API GatewayのAPIを作成します。
REST API
新しいAPI
を選択します。
統合タイプをLambda関数にして、Lambdaプロキシ統合の使用
にチェックを入れます。
チェックを入れることを忘れずに!!
API Gateway + Lambda + DynamoDBの連携をテスト
テスト本文にこちらを入力して実行します。
{
"url": "https://www.amazon.co.jp"
}
成功が帰ってきたらOK。お疲れ様でした。
最後に
次回はSAMで環境構築をコード化する、テストコードのパターンを増やす、追加したURLを取得するAPIを追加、などやる予定です。