APIGatewayとLambdaについてまとめる

# API GatewayとAWS Lambda
## はじめに
基本的な設定方法は以下のサイトを参考にしてください。
[【API Gateway】AWS Lambda統合のPythonでHello, world](https://qiita.com/baikichiz/items/2de7c4c0dcf9b051037a)

## 1.1. やろうとしていること
このパートでは、クライアントからの要求をAPI gatewayを通してLambdaで処理して何らかの反応を返すというもの
## 1.2. サービスの説明
### 1. API gatewayについて[1]
>API gateway : APIの作成と管理が簡単にできるサービス

>◯APIの作成：AWS Lambda、EC2、もしくはAWS外でパブリックとして公開されているアプリケーションをAPIとして公開することができます。<br>
>◯APIの管理：Amazon API Gatewayは、APIの管理に必要な以下のような事項をお客様側での実施が必要なく、AWS側で提供しています。

### 2. AWS Lambdaについて[2]
>Lambda : AWSに関するなにかしらのイベントによって処理を実行する環境

関数として処理を定義する。
### 3. bottleについて
bottle : Pythonで一番軽量なWEBフレームワーク<br>
lambda関数内の処理や、htmlの"form"から送られたpostの処理に利用する。特に考えるのはrequestオブジェクト。<br>
#### 各サブクラスについて
BaseRequestが親クラスとなって様々なサブクラスが作成される。
1. query
2. forms
3. files
4. params
5. json

特に送信データが写真のときは__multipart/form-data__になる。その場合用いるのは"files"クラス
#### filesクラス
メソッド
+ .get("KEY") : KEYに対応するVALUEのオブジェクトが取得できる
+ .filename : ファイル名が取得できる
+ .name : html内の"form"のnameが取得できる
+ .file : fileObject(BytesIO buffer or temporary file)を開くことができる

## 1.3. サービスの設定方法
### 1. API gatewayの設定

1. RESTfum APIの設定
    - メソッドの設定
    - 
```
/(GET)
　┗/check(POST)
```
<img width="446" alt="api_gateway_1_2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291611/3a4c5baa-6f6a-fd99-9e1e-e259f2a097c1.jpeg">
2. 「Lambdaプロキシ統合の使用」にチェック
 - これによってレスポンスの種類ごとにテンプレートを変更しなくて済む
<img width="434" alt="api_gateway_2_2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291611/37950605-1eff-085b-5159-bf13e16d350c.jpeg">
3. 「メソッドレスポンス」の設定変更
    - 「200のレスポンス本文」を”text/html”に変更
        →htmlファイルを表示させるため
<img width="429" alt="api_gateway_4_2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291611/af8044ef-d74e-09a2-3205-1111c1eb0089.jpeg">
4. それぞれのメソッドのテスト

### 2. Lambdaの設定
#### 手順
>1. 利用するファイルをまとめて圧縮
>2. AWS Lambdaの設定


#### 1. 利用するファイルをまとめて圧縮
```
今回使用したファイル集
・sample/
├ bottle.py　　　　　 # webフレームワーク
├ text_test.py　　　　# text送信の場合
├ photo_test.py　　　# 画像送信の場合
└ views/　　　　　　# htmlファイル
　　├ text_login.html
　　├ text_check.html
　　└ photo_login.html
```

##### 各コードサンプル
##### 1. テキストを送信する場合
##### text_test.py
```python:text_test.py
# coding:utf-8
from bottle import template
import urllib


# htmlファイルを返す関数
def login(event, context):
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "text/html"},
        "body": template('text_login')
    }

# postされた情報を加えたhtmlファイルを返す関数
def check(event, context):
    body = event['body']
    # application/x-www-form-urlencordedから適切な形に変換する
    body2 = urllib.parse.parse_qs(body)

    username = body2['username'][0]
    email = body2['email'][0]

    return {
            "statusCode": 200,
            "headers": {"Content-Type": "text/html"},
            "body": template('text_check', username=username, email=email)
    }
```
##### text_login.html
``` html:text_login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>メールアドレスと名前を送信してください</h1>
        <form method="post" enctype="application/x-www-form-urlencoded" action="/check">
            <input placeholder="名前" name="username" type="text"/>
            <input placeholder="メール" name="email" type="text"/>
            <input value="送信" type="submit"/>
        </form>
</body>
</html>
```
##### text_check.html
``` html:text_check.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>確認</h1>
        <h2>名前</h2>
            <p>{{ username }}</p>
        <h2>メールアドレス</h2>
            <p>{{ email }}</p>
</body>
</html>
```

##### 2. 画像を送信する場合
##### photo_test.py
```python:photo_test.py
# coding:utf-8
from bottle import template


# htmlファイルを返す関数
def show_page(event, context):
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "text/html"},
        "body": template('photo_login')
    }


# postされた画像の生データを表示
def check(event, context):
    photo_data = event['body']
    return {
            "statusCode": 200,
            "headers": {"Content-Type": "application/json"},
            "body": {"message": photo_data}
    }
```

##### photo_login.html
```html:photi_login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>PhotoTest</title>
</head>
<body>
<h1>Test</h1>
<h2>画像を挿入してください</h2>
<form method="post" enctype="multipart/form-data" action="/photo">
    <input placeholder="画像" name="photo" type="file" />
    <input placeholder="送信" type="submit" />
</form>
</body>
</html>
```
* 注意：htmlファイルのformタグの”action”はAPI gatewayでの「APIのデプロイ」が完了してから追加記入すること。宛先が異なると正しく動作しない。

#### 2. AWS Lambdaの設定
0. 使うファイルをzipで圧縮
1. AWS　Lambdaサイト内の「関数の作成」にて関数を設定後、zipファイルを転送
<img width="425" alt="lambda_1_2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291611/0c0ac90a-92dc-2db2-70a3-108f2ae14b67.jpeg">
2. AWS Lambda関数のトリガー作成
 - 今回はAPI gatewayをトリガーとする。各種設定を行い、二つの機能を接続する
3. サイト内の「テスト」にて正常に動くか試す。

## 1.4. 注意すべき部分
### IAMロールについて
AWSのサービス(API gateway, Lambdaなど)を利用する際、権限を設定する必要がある。<br>
一般には標準的なもので間に合うが、S3を用いたりEC2と通信したい場合は適切なIAMロールに変更する必要がある。
### proxyと本文マッピングテンプレートについて
API gatewayではレスポンスの形を適切に変更することが可能である。主に2つの整形方法がある。
1. プロキシ統合
2. マッピングテンプレートの利用

今回は1.のプロキシ統合を用いた。これにより、レスポンスの形が統一されるためLambdaで処理する方法が統一されるからである。
ただ、2.であればレスポンスを適切な形に整形してLambdaに送れるため処理が用意になるというメリットもある。[3]<br>
以下はformでpostしたデータを整形するためのマッピングテンプレートである。[4]

```
"queryParameters" : {
#set( $tmpstr = $input.body )
#foreach( $keyandvaluestr in $tmpstr.split( '&' ) )
#set( $keyandvaluearray = $keyandvaluestr.split( '=' ) )
        "$keyandvaluearray[0]" : "$keyandvaluearray[1]"#if( $foreach.hasNext ),#end
#end
}
```


## 参考サイト
[1] [5分でわかるAmazon API Gateway](https://recipe.kc-cloud.jp/archives/7944)<br>
[2] [AWS Lambda超入門](https://qiita.com/s_s_k/items/b584435120e99d63975b)<br>
[3] [API Gatewayの本文マッピングテンプレートを理解する](https://dev.classmethod.jp/cloud/aws/api-gateway-mapping-template/)<br>
[4] [API Gateway + Lambda にFormからPOSTする時のマッピングテンプレートを作成しました](https://dev.classmethod.jp/cloud/aws/sugano-013-api-gateway/)