AWS Lambda+API Gatewayハンズオンネタ

先日参加したJAWSDAYSでもいろいろ紹介されていたLambda。
社内勉強会で1時間半程度のハンズオンネタになったので、これから勉強する方に活用いただければと思って投稿します

## AWS Lambdaとは

実行されるインフラを意識せずにアプリケーションだけ実行できるサービスです。
[Developers Guide](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)によると、

> AWS Lambda は、コードを AWS Lambda にアップロードすると、サービスが AWS インフラストラクチャを使用してコードの実行を代行するコンピューティングサービスです。コードをアップロードして、Lambda 関数と呼ばれる関数を作成することで、AWS Lambda がコードを実行するサーバーのプロビジョニングおよび管理を行います。


## 実行環境

LambdaではNode.js/Python2.7/Java8が選択できますが、今回はPython2.7を使っています

## 1. はじめてのLambda

### デプロイするコードの作成

Lambdaで実行するサンプルプログラムとして「Chatworkに通知するBot」を題材にします。試してみたい方はAPItokenを取得し、投稿先のRoomIDを調べておいてください。

pythonのコードはこちら。APItokenとRoomIDは置き換えて使ってください。

```post_chatwork.py
# -*- coding: utf-8 -*-

import requests
import logging

api_token = '{your api token}'

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def post_message(room_id, message):
	url = 'https://api.chatwork.com/v1/rooms/{0}/messages'.format(room_id)
	headers = { 'X-ChatWorkToken' : api_token }
	payload = { 'body' : message }
	
	r = requests.post(url, headers=headers, data=payload )
	logger.info(r.text)

def lambda_handler(event, context):
	post_message('{room_id}', 'LambdaからHello,World')
```

これをAWSマネジメントコンソールで張り付けてもrequestsモジュールがないため使えません。以下のコマンドでrequestsモジュールをインストールする必要があります。

```
pip install requests -t <this directory>
```

その後、以下の3つをまとめてzip圧縮します。これらが存在するディレクトリごと圧縮ではなく、これらをそのまま圧縮しないといけないところだけ注意点です。

* 上記のpythonスクリプト
* requestsモジュールインストール後にできたrequestsディレクトリ
* requestsモジュールインストール後にできたrequests-2.9.1.dist-infoディレクトリ

### Lambda Functionの登録

AWSマネジメントコンソールから実施します。

1. Lambdaメニューを選択
2. [Create a Lambda Function]
3. blueprintを選ぶ部分はSkip
4. Configure Function
    * Name: Lambda Functionの名前
    * Runtime: Python2.7
    * Code entry type: Upload a .ZIP fileで先ほど作ったzipをupload
    * Handler: post_chatwork.lambda_handler
    * Role: Create New Role の S3 execution Role　※後でS3連携するため
    * 残りはデフォルトのまま
5. Next
6. Create Function

### テスト実行

LambdaFunctionの詳細画面で[Test]を実行。InputTestEventでInputとなるJSONを選択することになりますが、今はInputの情報を使っていないので「HelloWorld」を使い、[Save]して[Test]で実行されます。

下の方に実行ログも表示されます。Chatworkに通知がされていれば成功です。

### スケジュール実行

先ほど手動実行したLambdaFunctionを5分ごとに起動させてみます

1. LambdaFunctionの詳細画面を開く
2. [Event sources]タブを選択
3. [Add event source]
4. [CloudWatch Events - Schedule]を選択
5. [Schedule Expression]をrate(5 minutes)にして登録

これだけで5分間隔にスケジュール実行されます。スケジュールはcron形式の書き方もできますのでいろいろ試してみてください。

## 2. S3と連携したLambda

次はS3にファイルが置かれたらChatworkに通知する仕組みを作ってみます。
S3のバゲットの作成は事前に作成しておいてください。

### デプロイするコードの作成

今回はS3にファイルが置かれたイベントを受け取る部分が違います。

```post_chatwork_with_s3.py
# -*- coding: utf-8 -*-

import requests
import logging
import json
import urllib

api_token = '<api token>'

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def post_message(room_id, message):
	url = 'https://api.chatwork.com/v1/rooms/{0}/messages'.format(room_id)
	headers = { 'X-ChatWorkToken' : api_token }
	payload = { 'body' : message }
		
	r = requests.post(url, headers=headers, data=payload )
	logger.info(r.text)

def lambda_handler(event, context):
	
	#bucket = event['Records'][0]['s3']['bucket']['name']

	#日本語を含むファイル名だと文字化けしてしまいます
	key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')

	post_message('<room id>', u'S3に{0}がアップされました'.format(key))
```

その他は同じで、requestsモジュールと一緒にzip化します。

### Lambda Functionの登録

先ほどと同じ手順でできるので省略。

### Lambda Function自体のテスト実行

LambdaFunctionの詳細画面で[Actions]から[Configure test event]を選択。今回はS3のファイル登録をトリガにしますので[S3 - Put]を選んで[Save]して、テスト実行してください。

「S3にHappyFace.jpgがアップされました」と通知されたら成功です。

### S3と連携させる設定

1. LambdaFunctionの詳細画面を開く
2. [Event sources]タブを選択
3. [Add event source]
4. [S3]を選択
5. 用意したBucketを選択
6. EventTypeは[Object Created(All)]にして登録

これだけです。
S3の対象Bucketにファイルを置くと、Chatworkに通知がされるかと思いますので確認してみてください。

ただ、日本語を含むファイル名の場合は通知が文字化けが発生してしまいまして、解決できていません。ご了承ください。


## 3. API Gatewayと連携したLambda

API Gatewayを使って、外部からAPIを叩くことでLambda関数を実行できるようにしたいとおもいます。Lambda関数については「1.はじめてのLambda」で使ったものを再利用します。

### API Gatewayの設定

1. LambdaFunctionの詳細画面を開く
2. [API endpoints]タブを選択
3. [Add API endpoint]
4. 自己責任でお願いしたいのですが、さくっと試してみるだけなら以下のようにして登録
    * Method: GET
    * Security: OPEN(認証なし)
5. しばらくすると[API endpoint URL]が表示されるので、リンクをクリックするとLambdaが実行される

認証なしのAPIを放置するのはあまりよくないので、試し終わったら削除しておくことだけ忘れないようにご注意ください。

終わり。