serverless framworkでLambda＋APIGatewayをdeployする

## はじめに
アプリケーションを Lambda にデプロイする際どんな方法を使用しているだろうか？
AWS SUM ,code deploy と使用してきたがコマンドを複数回叩かないといけなかったりとちょっと面倒臭かった。
そこで最近自分の周りで話題になっている serverless framwork を試してみる。
何やらコマンド一つでビルド・デプロイを行ってくれたりとかなり便利らしい。
<img width=100% alt="スクリーンショット 2020-02-09 11.34.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472784/33ed681a-a8c7-c0fd-24ee-a70dd4f7e503.png">

## Serverless Framework インストール
以下のコマンドを実行し Serverless Framework をインストールする。

```
$ npm install -g serverless
```

> ローカル端末で Serverless Framework を利用する場合は別途 Credentials の設定が必要になる。

## サービス作成
Serverless Framework のサービスを作成する。
今回は`create-stock-price-index`というサービス名で、`Python 3.6`の Lambda ファンクションを作成する。

```
$ serverless create --template aws-python3 --path create-stock-price-index
```
`create-stock-price-index`ディレクトリ配下に以下のファイルが作成される。

- serverless.yml
- handler.py

今回の deploy では`handler.py`を[こちら](https://qiita.com/Nidhog-tm/items/5221fbe2993eca6364ed)で作成したコード`app.py`に置き換える。
あわせて、`serverless.yml`も以下のように変更しておく。

```serverless.yml
service: create-stock-price-index

provider:
  name: aws
  runtime: python3.7
  region: ap-northeast-1

functions:
  get-policy-number-list:
    handler: app.lambda_handler
```

## 外部モジュールのインストール
いざ deploy と行きたいところだが、`app.py`は以下のように標準で同梱されている以外の外部モジュールを使用している。

```app.py
import requests
from bs4 import BeautifulSoup
import yaml
```

この外部モジュールの管理について今回は [UnitedIncome/serverless-python-requirements](https://github.com/UnitedIncome/serverless-python-requirements) いう Serverless Framework のプラグインを使用する。
まず、プラグインをインストールする。
Serverless Framework で管理しているディレクトリ上で以下のコマンドを実行する。

```
$ npm install --save serverless-python-requirements
```
続いて、`serverless.yml`に plugins を追加する。
plugins プロパティで利用するプラグインを指定する。

```serverless.yml
service: create-stock-price-index

provider:
  name: aws
  runtime: python3.7
  region: ap-northeast-1

plugins:
  - serverless-python-requirements

functions:
  get-policy-number-list:
    handler: app.lambda_handler
```

最後に、`requirements.txt`を用意する。
`requirements.txt`には import する外部モジュールとその依存関係を記載する。

```requirements.txt
beautifulsoup4==4.8.2
certifi==2019.11.28
chardet==3.0.4
idna==2.8
PyYAML==5.3
requests==2.22.0
soupsieve==1.9.5
urllib3==1.25.7
```

## デプロイ
前項まででデプロイの準備が整ったのでいよいよデプロイを実行していく。
`create-stock-price-index`ディレクトリに移動し、デプロイコマンドを実行する。

```
$ sls deploy -v
```
>ここで pip と setuptools のバージョンが古いとエラーが出たのでアップデートする。
すると、 CloudFormation により必要なリソースを作成し、 Lambda ファンクションがデプロイされた事が確認できる。
<img width="1281" alt="スクリーンショット 2020-02-04 22.33.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472784/8868d8f7-7313-641e-796a-238729bea700.png">

デプロイした Lambda を実行してみる。

```json

$ sls invoke -f get-policy-number-list
{
    "投資指標": [
        {
            "証券コード": 3242,
            "予想PER": "7.77倍",
            "予想EPS": "46.2",
            "実績PBR": "1.08倍",
            "実績BPS": "332.15",
            "予想配当利": "6.69％"
        },
        {
            "証券コード": 9904,
            "予想PER": "15.88倍",
            "予想EPS": "22.1",
            "実績PBR": "1.79倍",
            "実績BPS": "196.51",
            "予想配当利": "5.68％"
        }
    ]
}
```
問題なく実行でき、期待通りの結果を得る事ができた。

## API Gateway 作成
API Gateway を構築することでエンドポイントに対する Get リクエストをトリガーに Lambda を実行することができる。
`serverless.yml`に Lambda ファンクションを呼び出すためのイベントを定義する。

```yml:serverless.yml
service: create-stock-price-index

provider:
  name: aws
  runtime: python3.7
  region: ap-northeast-1

plugins:
  - serverless-python-requirements

functions:
  get-policy-number-list:
    handler: app.lambda_handler
    events:
      - http:
          path: /
          method: get
          integration: lambda
          request:
            template:
              application/json: '{ "user_id" : "$input.params("password")" }'
```

デプロイコマンドを実行する。

```
api keys:
  None
endpoints:
  GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/
functions:
  get-policy-number-list: create-stock-price-index-dev-get-policy-number-list
layers:
  None
```

デプロイが完了すると ServiceEndpoint が出力される。
このエンドポイントに対してGetリクエストを送ってみる。
> Unicodeが文字化けするのでちょっと細工する。

```
$ curl -X GET "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/"  | perl -Xpne 's/\\u([0-9a-fA-F]{4})/chr(hex($1))/eg'
{"投資指標": [{"証券コード": 3242, "予想PER": "7.81倍", "予想EPS": "46.2", "実績PBR": "1.09倍", "実績BPS": "332.15", "予想配当利": "6.65％"}, {"証券コード": 9904, "予想PER": "16.02倍", "予想EPS": "22.1", "実績PBR": "1.8倍", "実績BPS": "196.51", "予想配当利": "5.63％"}]}
```
期待値通りの結果が出力された。

## リソースの削除
一通り確認が終わったらAWS上のリソースを削除しておく。

```
$ sls remove -v
```

## おわりに
簡単なインストールと設定で準備を整える事ができ、その上コマンド一つでデプロイ、スタックの削除と行えるなはかなり便利だった。
パッケージ管理についてもプラグインをインストールするだけで`requirements.txt`がそのまま使用できたのも好印象だった。