はじめに

こちらの記事はGoとAPI Gateway + Lambda + DynamoDBでサーバレスなAPIを作る記事となっています。
前回の記事の続きとなっているため、一部手順を省略しています。

はじめにこの記事はGoでLambda Function URLsをハンズオンしてみる内容となっています。筆者がLambdaでGoを扱うこと自体が初めてだったため備忘録として簡単に環境構築からデプロイまでの手順も載せています。...
はじめにこの記事はLambda(Function URLs)とDynamoDBと連携させる内容となっています。前回の記事の続きとなっているため同様の手順は省略しています。環境MacBook Air M1開発言語 Go...

環境

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

ソースコード

API Gateway, Lambda, DynamoDB. Contribute to tkhs1121/go-serverless-app-3 development by creating an account on GitHub.

一部抜粋

main.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)
}

common.go

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
}

infra.go

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のテーブルを作成

DynamoDBのテーブルを作成します。

⚠パーティションキーとソートキーが数値となっている点に注意してください!

Lambda + DynamoDBの連携をテスト

テストのイベント作成して、テンプレートからapigateway-aws-proxyを選択してイベント JSONのbodyを変更します。

  "body": "{\"url\": \"https://www.amazon.co.jp\"}",

テストを実行して成功が返ってきたらOKです。

API Gatewayとの連携

API GatewayのAPIを作成します。
REST API 新しいAPIを選択します。

アクションタブからメソッドの作成 POSTを選択します。

統合タイプをLambda関数にして、Lambdaプロキシ統合の使用にチェックを入れます。

⚠チェックを入れることを忘れずに!!

API Gateway + Lambda + DynamoDBの連携をテスト

テスト本文にこちらを入力して実行します。

{
    "url": "https://www.amazon.co.jp"
}

成功が帰ってきたらOK。お疲れ様でした。

最後に

次回はSAMで環境構築をコード化する、テストコードのパターンを増やす、追加したURLを取得するAPIを追加、などやる予定です。

元記事はこちら

Go+API Gateway+Lambda+DynamoDBでサーバレスなAPI
著者:
@tkhs1121