API Gateway と Lambdaでお問い合わせフォームを作る

[Gaiax Advent Calender 2016](http://qiita.com/advent-calendar/2016/gaiax)の25日目の記事です。AIRY事業部の三井です。

少し前に製品サイトの環境構築に携わりました。静的コンテンツのホスティングだけであればS3だけでよいと思うのですが、お問い合わせフォームを設けたかったのでサーバ立ててまっさらな状態から構築しました。しかし最近では動的コンテンツもAPI GatewayとLambdaを使うとサーバレスで実現できるそうなので試してみました。
今回は手元のお問い合わせフォームから送信した情報をAPI GatewayとLambdaを使ってS3に保存してみます。

公式の[Lambda 関数を公開するための API を作成する](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/getting-started.html#getting-started-new-lambda)を参考に進めています。

## 構成
![AWS Design.png](https://qiita-image-store.s3.amazonaws.com/0/96480/07292c28-3988-44d9-98d0-cfb27d19df2a.png "AWS Design.png")
ユーザのリクエストをAPI Gatewayが受けて、それをトリガーにLamdaの関数が実行され、S3にデータが保存されるようにします。
## Lambda関数の作成

![スクリーンショット_2016-12-25_10_34_54.png](https://qiita-image-store.s3.amazonaws.com/0/96480/dc066da9-ac1b-345e-c124-58ddc3495e99.png "スクリーンショット_2016-12-25_10_34_54.png")
Lambdaの管理画面で「Get Started Now」をクリックします。


![スクリーンショット_2016-12-25_10_44_14.png](https://qiita-image-store.s3.amazonaws.com/0/96480/7fba1ee0-a595-cc82-8000-b1a4522295a6.png "スクリーンショット_2016-12-25_10_44_14.png")
左の「Configure function」をクリックします。
Nameに関数名を入力します。今回はcreateProposalとしました。
テキストエリアに処理の内容を記述します。Lambda上ではaws-sdkというnode向けのSDKが使え、それでS3を操作します。ちなみにリファレンスはこちらです。http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html

```javascript
'use strict';

console.log('Loading function');

const AWS = require('aws-sdk');
AWS.config.update({
  accessKeyId: 'xxx',
  secretAccessKey: 'yyy',
  region: 'ap-northeast-1'
});

const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

exports.handler = (event, context, callback) => {
  const params = {
    Bucket: 'Bucket Name',
    Key: 'File Name',
    Body: JSON.stringify(event),
    ACL: 'public-read'
  };

  s3.putObject(params, (err, data) => {
    if (err) {
      callback(null, { status: 'NG' });
    } else {
      callback(null, { status: 'OK' });
    }
  });
};
```

![スクリーンショット_2016-12-25_11_08_59.png](https://qiita-image-store.s3.amazonaws.com/0/96480/fed48d17-b897-cad1-9e65-4f3511e1b0dc.png "スクリーンショット_2016-12-25_11_08_59.png")

下にスクロールしてRoleの設定をします。マニュアルに倣って以下の値にしました。
Role: Create new role from template(s)
Role Name: execute_my_lambda

「Next」をクリックすると確認画面に遷移するので「Create Function」をクリックするとLambda関数が作成されます。

## API Gateway作成
![スクリーンショット_2016-12-25_11_20_52.png](https://qiita-image-store.s3.amazonaws.com/0/96480/e0730094-587b-b1f0-c46a-31dd496e6ef3.png "スクリーンショット_2016-12-25_11_20_52.png")
API Gatewayの管理画面で「今すぐ始める」をクリック。

![スクリーンショット_2016-12-25_11_21_20.png](https://qiita-image-store.s3.amazonaws.com/0/96480/bf1285db-54a0-19f3-f293-87f82ad3177f.png "スクリーンショット_2016-12-25_11_21_20.png")
「新しいAPI」を選択し、「API名」を入力、「APIの作成」をクリック。これでAPIが作成されるので、リソースとメソッドを追加し、Lambda関数とひも付けていきます。

![スクリーンショット_2016-12-25_11_28_12.png](https://qiita-image-store.s3.amazonaws.com/0/96480/2c37061e-cfd2-d9ee-4026-6f4dcecfc96c.png "スクリーンショット_2016-12-25_11_28_12.png")
「アクション」をクリックして、リソースの作成をクリックします。

![スクリーンショット_2016-12-25_11_28_37.png](https://qiita-image-store.s3.amazonaws.com/0/96480/fbfccbaa-ba12-c154-885f-608456c91aad.png "スクリーンショット_2016-12-25_11_28_37.png")
「リソース名」と「リソースパス」を入力し、「リソースの作成」をクリックします。

![スクリーンショット_2016-12-25_11_29_12.png](https://qiita-image-store.s3.amazonaws.com/0/96480/7de754ad-c3c8-be53-13b7-3dcb50b07b78.png "スクリーンショット_2016-12-25_11_29_12.png")
リソースを追加したときと同様に「アクション」から「メソッドの作成」をクリックします。申し込み内容を保存するAPIなのでPOSTを選択し、右のチェックボタンをクリックします。

![スクリーンショット_2016-12-25_11_39_15.png](https://qiita-image-store.s3.amazonaws.com/0/96480/5e053a99-c292-fade-3f17-6a1f63be01b6.png "スクリーンショット_2016-12-25_11_39_15.png")
「アクション」から「APIをデプロイ」をクリックするとダイアログが立ち上がるので「ステージ名」を入力して「デプロイ」をクリック。

![スクリーンショット_2016-12-25_12_32_15.png](https://qiita-image-store.s3.amazonaws.com/0/96480/aed5892a-7998-6ba5-d21b-19580a081692.png "スクリーンショット_2016-12-25_12_32_15.png")
「ステージ」をクリックすると、作成したステージが表示されており、公開URLを確認できます。

## お問い合わせフォーム作成
```
<script>
  $(function() {
    $('#form').on('submit', function(event) {
      event.preventDefault();

      var params = {};
      $($(this).serializeArray()).each(function(i, v) {
          params[v.name] = v.value;
      });

      $.ajax({
        url: "https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/proposal",
        method: "POST",
        data: JSON.stringify(params),
        success: function (res) { console.log(res) },
      });
    });
  });
</script>
```

![スクリーンショット 2016-12-25 12.53.20.png](https://qiita-image-store.s3.amazonaws.com/0/96480/f21b56dc-4334-2e57-72e3-e231c6fab640.png "スクリーンショット 2016-12-25 12.53.20.png")
こんな感じで作ってみました。送信をクリックすると


![スクリーンショット 2016-12-25 12.54.24.png](https://qiita-image-store.s3.amazonaws.com/0/96480/91ef4bea-2fc7-ddf8-fd25-aeddef73b1c4.png "スクリーンショット 2016-12-25 12.54.24.png")
S3にファイルが作られていました。

```
{"company":"ガイアックス","name":"田中太郎","email":"sample@example.com","proposal":"メリークリスマス"}
```
中身はこんな感じで、送信されたデータを保存することができました。

## 感想
本番で使うとなると、更に細かく設定を見ていかないといけないと思うのですが、とても簡単にお申し込みフォームを作ることができました。アプリもこれでいいんじゃないかなと思いました。

それでは皆様一年間お疲れ様でした！よいお年を〜

## 参考
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-create-resource-and-methods.html
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/getting-started.html#getting-started-new-api
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html