0
Help us understand the problem. What are the problem?

posted at

updated at

Organization

Go+API Gateway+Lambda+DynamoDBでサーバレスなAPI

はじめに

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

環境

MacBook Air M1
開発言語 Go

手順

Lambda関数の作成

一から作成のままランタイムをGo.1.x アーキテクチャをx86_64にして関数の作成をします。
Lambda.png

必要なパッケージのインストール

go get -u github.com/aws/aws-sdk-go
go get -u github.com/aws/aws-lambda-go

ソースコード

一部抜粋

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ファイルを選択してアップロードします。
Lambda2.png

ハンドラの名前を初期のhelloからhandlerに変更します。
Lambda3.png

DynamoDBの作成とLambdaに実行ロール追加

設定からロール名 ロールの許可ポリシー までいったら、
ポリシーの編集 を選択してビジュアルエディタでDynamoDB PutItemのアクションを追加します。
Lambda5.png
Lambda6.png

DynamoDBのテーブルを作成

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

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

Lambda + DynamoDBの連携をテスト

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

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

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

API Gatewayとの連携

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

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

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

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

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

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

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

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

最後に

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

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?