TOP ▲
itcore TOP
> TIPS
> go_api.php
タグ:go lambda dynamodb api gateway ソース GO+Lambda+DynamoDB+API Gateway サンプルソース | itcore 2021年
main.go
package main
//-------------------------------------
// get-api/main.go DBのレコードを返す。
//-------------------------------------
import (
"bytes"
"context"
"encoding/json"
"errors"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-lambda-go/lambdacontext"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"log"
"strconv"
"strings"
"time"
)
// 定数
const Version = "0.1"
const FuncName = "get" // 関数名 ログ用
const ApiKey = "xxx" // 外部で管理する
const HeaderApiKey = "X-Api-Key" // カスタムヘッダキー 先頭大文字のキャメル 文字とする。
// グローバル変数
var req RequestBody // リクエストデータ
var dbTable1 DbTable1 // DBデータ
var ErrorMessage = ""
var StatusCode = 200
// 長い型の別名
type (
Request = events.APIGatewayProxyRequest
Response = events.APIGatewayProxyResponse
)
// リクエスト Body
type RequestBody struct {
Id string `json:"id"` // ID
}
// バリデーション関数
func (req RequestBody) Validation() error {
err := ""
if "" == req.Id {
err += "idを指定してください。\n"
}
if "" != err {
return errors.New(err)
}
}
// レスポンスデータ
type ResponseBody struct {
Version string `json:"version"` // バージョン
ErrorMessage string `json:"error_message"` // エラーメッセージ
Id string `json:"id"` // ID
Name string `json:"name"` // 名前
}
// レスポンスを作成する。
func MakeRes() (Response, error) {
// レスポンスとして返すjson文字列を作る
res := ResponseBody{
Version: Version,
ErrorMessage: ErrorMessage,
Id: req.Id,
Name: dbTable1.Name,
}
jsonBytes, _ := json.Marshal(res)
log.Println("[" + FuncName + "] end status=" + strconv.Itoa(StatusCode) + " " + ErrorMessage) // ログ出力
return Response{
Headers: map[string]string{
"Content-type": "application/json",
// CORS対応
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Max-Age": "3600",
// カスタムヘッダのCORS許可はうまくいっていない。
"Access-Control-Allow-Headers": "X-Api-Key",
"Access-Control-Expose-Headers": "Access-Control-Request-Headers",
},
Body: string(jsonBytes),
StatusCode: StatusCode,
}, nil
}
// DynamoDB テーブルデータ
type DbTable1 struct {
Id string `dynamodbav:"id" json:id` // ID
Name string `dynamodbav:"name" json:name` // 名前
}
// APIハンドラ
func handler(ctx context.Context, request Request) (Response, error) {
// ログを日本時間にする。
time.Local = time.FixedZone("Asia/Tokyo", 9*60*60)
log.Println("[" + FuncName + "] start") // ログ出力
// リクエストデータ
req.Id = request.QueryStringParameters["id"] // ID
// ヘッダ APIキー認証
if _, ok := lambdacontext.FromContext(ctx); !ok {
ErrorMessage = "lambdacontext.FromContext ERROR122"
StatusCode = 400
return MakeRes()
}
// API Gateway経由だとカスタムヘッダのキーが小文字に変換される。
// 以下の記事を参考にすると良いかも
https://qiita.com/yuki_inoue/items/27555595b252923efe44
api_key, _ := request.Headers[strings.ToLower(HeaderApiKey)]
if "" == api_key {
// ローカルだとカスタムヘッダのキーが先頭大文字のキャメル文字に変換される。
api_key, _ = request.Headers[HeaderApiKey]
}
if ApiKey != api_key {
// ブラウザのajaxからヘッダを送るとCORSエラーになるので一旦チェックを無 効にする。
// bodyに持たせると良いかも
log.Println("[" + FuncName + "] APIキーエラー")
// ErrorMessage = "正しい認証キーを指定してください。"
// StatusCode = 400
// return MakeRes()
}
// バリデーション
if err := req.Validation(); err != nil {
ErrorMessage = err.Error()
StatusCode = 400
return MakeRes()
}
//----------
// DynamoDB
//----------
// DB接続
sess, err := session.NewSession()
if err != nil {
ErrorMessage = "session.NewSession ERROR156 " + err.Error()
StatusCode = 400
return MakeRes()
}
db := dynamodb.New(sess)
// 検索条件
getParam := &dynamodb.GetItemInput{
TableName: aws.String("table1"),
Key: map[string]*dynamodb.AttributeValue{
"id": {
S: aws.String(req.Id),
},
},
ConsistentRead: aws.Bool(true), // 整合性のある読み込み
}
// 検索実行
result, err := db.GetItem(getParam)
if err != nil {
ErrorMessage = "db.GetItem ERROR176 " + err.Error()
StatusCode = 400
return MakeRes()
}
// 検索結果
err = dynamodbattribute.UnmarshalMap(result.Item, &dbTable1)
if err != nil {
ErrorMessage = "dynamodbattribute.UnmarshalMap ERROR184 " + err.Error()
StatusCode = 400
return MakeRes()
}
// DB取得内容 ログ出力
var buf bytes.Buffer
json, _ := json.Marshal(dbTable1)
buf.Write(json)
log.Println("[" + FuncName + "] DynamoDB dbTable1 =" + buf.String())
//-----------
// 正常終了
//-----------
return MakeRes()
}
func main() {
lambda.Start(handler)
}samconfig.toml
version = 0.1
[default.deploy.parameters]
stack_name = "get-api"
s3_bucket = "itcorejp_dev"
s3_prefix = "get-api"
region = "ap-northeast-1"
confirm_changeset = false
capabilities = "CAPABILITY_IAM"template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
get-api
SAM Template for get-api
Globals:
Function:
Timeout: 5
Resources:
GetApiFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: get-api/
Handler: get-api
Runtime: go1.x
Tracing: Active
Events:
CatchAll:
Type: Api
Properties:
Path: /get_api
Method: GET
Environment:
Variables:
PARAM1: VALUE
Outputs:
GetAPI:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/get_api/"
GetApiFunction:
Value: !GetAtt GetApiFunction.Arn