LoginSignup
0
0

More than 3 years have passed since last update.

AWS DynamoDB を API Gateway で変更する

Posted at
  • 目的
    • AWS Lambda の設定値を変更したい
  • 背景
    1. 社内向けのLambdaがあり「AWS LambdaのJsonを編集してください」が他の部署では敷居が高い。
    2. config.jsonをS3に置いたりしたが、S3は直接プレビューできなかったり。
    3. DynamoDBがコード的にも楽だった。
  • 作業
    • DynamoDB を使ってAPI Gateway→Lambda→DynamoDB で値を変更。
  • 利点
    • 完全サーバーレス!
  • 補足
    • 今回の記事はDynamoDBを変更するLambdaです。運用中のLambdaは別です。

完成イメージ

  • DynamoDB を Web で変更できます。


AWS Lambda

  • GET のとき、DynamoDB を読み込んで Json を返します。
  • PUT のとき、DynamoDB を Update します。PUT の Json は引数の event に入ります。
python
import boto3
import json

def lambda_handler(event, context):
    message = {'message':''}
    table= boto3.resource('dynamodb').Table('test1')

    id = event.get('id', None)
    name = event.get('name', None)
    val1 = event.get('val1', None)
    val2 = event.get('val2', None)

    # PUT のとき
    if id:
        r = table.update_item(
            Key={'id': int(id)},
            UpdateExpression="set #name=:n, val1=:v1, val2=:v2",
            ExpressionAttributeNames= {'#name':'name'},
            ExpressionAttributeValues={':n':name, ':v1':val1, ':v2':val2}
        )
        return message

    # GET のとき
    list = []
    records = table.scan()
    records['Items'] = sorted(records['Items'], key=lambda x:x['id'])
    for r in records['Items']:
        try:  
            list.append({
                'id':r['id']
                ,'name':r['name']
                ,'val1':r['val1']
                ,'val2':r['val2']
             })
        except Exception as err:
            print('error except ', err)
    message['list'] = list
    return message

補足

  • IAM ロールに DynamoDB のアクセス権限を付けてください。
  • errorMessage "An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: name", というエラーが出たとき、上記のように {'#name':'name'} としてください。理由:name という名前は使用できない為。

API Gateway

  • API Gateway で HTML を返します。これで簡単なWebページが作れます。

APIタイプ REST API
結合タイプ Lambda
GET- メソッドレスポンス レスポンス本文を json から text/html に変更
GET- 統合レスポンス マッピングテンプレートを json から text/html に変更

API Gateway で HTML を返す

  • 統合レスポンス マッピングテンプレートの text/html に以下をコピーします。

html
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Test</title>
    <style>
        body{ padding:20px; }
    </style>
</head>

<body>
    <div id="list"></div>
</body>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
var API_URL = 'https://xxxx.execute-api.ap-northeast-1.amazonaws.com/1/';
var data = {
    list: '$input.path("$.list")'
}
redraw();

function redraw() {
    if (data['list']) {
        var t = "";
        t += '<table>';
        t += '<tr><th>id<th>name<th>val1<th>val2<th>';
        JSON.parse(data['list']).forEach(function(d) {
            var id = d['id'];
            t += '<tr><td>'+d['id'];
            t += '<td><input type="text" id="name'+id+'" value="'+d['name']+'">';
            t += '<td><input type="text" id="val1'+id+'" value="'+d['val1']+'">';
            t += '<td><input type="text" id="val2'+id+'" value="'+d['val2']+'">';
            t += '<td><input type="button" value="Put" onClick="put('+id+')">';
        });
        t += '</table>';
        $("#list").html(t);
    }
}

function put(id) {
    var n = document.getElementById("name"+id).value;
    var v1 = document.getElementById("val1"+id).value;
    var v2 = document.getElementById("val2"+id).value;
    var json = '{"id":"'+id+'", "name":"'+n+'", "val1":"'+v1+'", "val2":"'+v2+'"}';
    putjson(json);
}

function putjson(json) {
    $.ajax({
        url: API_URL,
        type: 'PUT',
        contentType: 'application/json',
        dataType: 'json',
        data: json,
    }).then(
        data => redraw(data),
        error => alert('error')
    );
}
</script>
</html>

API Gateway をIPアドレスで制限

  • API Gateway は誰でもアクセスできてしまうので、会社のグローバルIPで制限します。

API Gateway リソースポリシー IP 範囲の許可リスト

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "arn:aws:execute-api:ap-northeast-1:xx:xx/*/GET/",
                "arn:aws:execute-api:ap-northeast-1:xx:xx/*/PUT/"
            ],
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/32",
                        "xxx.xxx.xxx.xxx/32"
                    ]
                }
            }
        }
    ]
}

補足

  • arn はリソースに書いてあります。
  • 変更後リソースをデプロイして1分待ちます。

まとめ

AWS Lambda と DynamoDB と API Gateway だけで簡単なWebページが作れました。これだけでちょっとしたシステムが作れそうです。もうこれでええやん。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0