- 目的
- AWS Lambda の設定値を変更したい
- 背景
- 社内向けのLambdaがあり「AWS LambdaのJsonを編集してください」が他の部署では敷居が高い。
- config.jsonをS3に置いたりしたが、S3は直接プレビューできなかったり。
- 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ページが作れました。これだけでちょっとしたシステムが作れそうです。もうこれでええやん。