API GatewayからLambdaをぶっ叩く!! 〜HTMLフォームからslackへ投稿しよう〜


コンソール上でのAPI Gateway の使い方を確認していきます。
以前頑張って作って忘れたので備忘録兼ねて投稿

###APIGateway
![ダウンロード.jpeg](https://qiita-image-store.s3.amazonaws.com/0/52141/9f779e14-3b50-b4a5-26e6-17e12e319e8e.jpeg)

- APIのラッパーとして使える
- AWS Lambda（以下 Lambda)のトリガーとして使用できる
- APIコールのスロットリングが可能
- Mappingテンプレートを使用することで入力値と出力値の整形が出来る
- IAMと組み合わせた権限制御が可能
- お金は気にするほどでない

雑にいうとこんな感じのサービス。
今回は別途定義するLambdaのファンクションを呼び出します。

###ゴール
__クライアント上にサンプルのHTMLファイルを配置し、フォームに文字列を入力、送信ボタンを押すことでslackへ投稿が出来るようにします__

###HTMLファイルの準備

```html:index.html
<!DOCTYPEhtml>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>

<body>
<header>
    <h1>API GateWay test</h1>
</header>
  <p>Slack post api</p>
<article>
    <form action="後ほど作成するAPI Gatewayのエンドポイント" method="post" accept-charset="utf-8">
        <input type="text" name="message" placeholder="送信文字列を入力"/>
        <input type="submit" value="送信">
    </form>
</article>
</body>
</html>
```

テキストエディタでこのファイルを作成するとブラウザで以下のページが見れます

![TEST.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/b06ce233-8617-ee0f-8067-fc3facfff5dd.jpeg "TEST.jpg")

このページで送信ボタンを押すとAPI Gatewayにフォーム中の文字列を送信し、API GatewayからLambdaのファンクションが起動してslackへbotが投稿する

という動きになります。

では作っていきましょう。

まず、Lambdaのファンクションを定義します。

###Lambdaファンクション

```python:lambda_function.py
# -*- coding: utf-8 -*-
import slackweb
import urllib

SLACK_POST_URL = "slackのPOST用URL"

def lambda_handler(event, context):
    print(event)
    test_user = 'api-test'
    icon_emoji = ':moyashi:'
    slack_massage = urllib.unquote(event['message']).encode('raw_unicode_escape').decode('utf-8')
    slack_post(test_user, icon_emoji, slack_massage)
    print(slack_massage)

def slack_post(user, icon, massage):
    slack = slackweb.Slack(url=SLACK_POST_URL)
    slack.notify(text=massage, username=user, icon_emoji=icon)

```

今回は __slackweb__ というモジュールを使用してslackへ投稿しているのでクライアントで環境を作成し、ZIP化してLambdaへアップロードします。

この辺は省略しますが、詳しい手順は[ここ](https://www.hands-lab.com/tech/entry/1077.html)を参考にして下さい。

###API Gatewayの登録
では今回の目的、API GateWayです


マネジメントコンソールから

![AWS_mmg.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/ea7a1c44-34f0-a7e1-1f8b-db9500b59c5e.jpeg)


API Gatewayを選択

![API_Gateway.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/6cb86046-9bd3-4545-38c3-01ff16eb40bd.jpeg)

Create API を押下
APIの作成画面が表示されるので

![API_Gateway2.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/ac53d524-f785-703b-1e06-2b108ede13ac.jpeg)

API Nameに任意の名前を入力し、説明を付けたらCreate APIを押下

###リソースの作成

![API_Gateway001.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/e526df3f-eda0-ffbe-bbc7-59923495400d.jpeg "API_Gateway001.jpg")

Actionsタブ内のCreate Resource を選択します

![API_Gateway002.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/9176157a-30c8-b093-8e62-c3d0862a61bb.jpeg "API_Gateway002.jpg")

公開するAPIのバージョンを作成します。
外部のAPIとかみてもバージョン入ってるので管理のためにやっておいたほうが良いんだろうなという認識です。
リソースのトップにバージョン番号を入れているのは[AWSエキスパート養成読本](http://gihyo.jp/book/2016/978-4-7741-7992-6)でやっていたので真似ることにしています。

同じ手順でリソースを作ります。
v1の下にslackを作成して下さい。

次はメソッドを追加します

###POSTメソッドの作成

slackを選択している状態で作業します

![API_Gateway003.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/c079eb90-d8cd-5e3a-584e-b43c9d4b111c.jpeg "API_Gateway003.jpg")

Create Methodを選択します

![API_Gateway004.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/614984cb-561d-9b39-adf4-d776e07bfb0a.jpeg "API_Gateway004.jpg")

メソッドを作成したら、メソッドの裏側を設定します。
今回は作成しておいたLambdaのファンクションを指定します

![API_Gateway005.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/c36b8c04-2e42-3fed-dcf6-8d54a47508a4.jpeg "API_Gateway005.jpg")

ポップアップが出てくるのでOKして進みます
![API_Gateway006.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/f5f41587-be4c-956b-6a5c-6a506775db2b.jpeg "API_Gateway006.jpg")

入力値を弄るため Integration Request を押下します。


![API_Gateway007.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/2206779e-572b-17f8-f900-8884509a4b0e.jpeg "API_Gateway007.jpg")

Content-Typeは __application/x-www-form-urlencoded__ を指定します。
ポップアプが出てくるのでOKします

```VTL:マッピングテンプレート
#set($http = $input.path('$').split("&"))
#set($kv = $http[0])
 #set($key = $kv.split("="))
 {
  "message" : "$key[1]"
  }
```

マッピングテンプレート表記に関しては以下を参考にして下さい
[API Gateway のマッピングテンプレートリファレンス](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html)

HTMLのPOSTリクエストの形式は[この記事](http://qiita.com/satetsu888/items/40fc387735192b794da8)を参考にして把握しました。ありがとうございます
> HTMLフォームによるPOSTリクエストでは、各inputタグの内容をkey=valueの形式として&でつないだものがリクエストボディとして送信されます。

とのことだったので、Body部分を分割して、その中から＝れ連結されているValueを取得し、JSONになおしています。

```json:json
 {
  "message" : "$key[1]"
  }
```

実際にLambdaに送られるのはこのJSONメッセージになるって寸法です

###デプロイ
![API_Gateway008.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/7efa1698-c5ef-bbbb-8287-e5c65cb55748.jpeg "API_Gateway008.jpg")


![API_Gateway009.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/36d7d10d-c712-e961-ad85-a77fd1e57835.jpeg "API_Gateway009.jpg")

こんな感じでステージを作ってデプロイします

![API_Gateway010.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/ea9bd231-b2af-b397-8a0c-c10de1edca30.jpeg "API_Gateway010.jpg")

するとこんな感じで投稿用のURLエンドポイントが取得できるのでコレをHTMLに埋め込みます
フォームタブ野中ですね。

###投稿
では作成したHTMLから投稿してみます

![TEST.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/3699add3-7db7-edf1-ca94-7926f6a06986.jpeg "TEST.jpg")

文字列を入力して送信を押すと・・・

![Slack.jpg](https://qiita-image-store.s3.amazonaws.com/0/52141/1a4a3f36-baad-1723-6555-9cec9d56399b.jpeg "Slack.jpg")

無事slackへ投稿が出来ました。
API　Gatewayは組み合わせればいろいろと遊べるので試していきたいです。

###参考
http://qiita.com/satetsu888/items/40fc387735192b794da8
http://wiki.mesolabo.com/?%E3%83%A1%E3%82%BD%E7%9F%A5%E6%81%B5%2FHTML%2F%E9%81%95%E3%81%86%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7POST%E3%81%99%E3%82%8B
http://linux.oboe-gaki.com/archives/000333.html