Serverless Framework(APIGateWay+Lambda+DynamoDB)でのリダイレクト

# 要件
pathパラメータをキーにDynamoDBに格納されているURLへリダイレクトさせる。

# アーキテクチャ
<img width="494" alt="architecture.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/9362e696-5325-451a-c64b-2d0ee14e0c29.png">


2018/11/05にAPIGatewayでWAFを有効化できるようになりました(ワーイ)

# APIGateway設定
#### 新規作成
<img width="1122" alt="apigatewaynew.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/0498552c-f358-580e-812c-f6460ad75144.png">

※ちょうど先日(2018/12/18)APIGatewayで **WebSocketAPI** の構築が出来るようになったのですが、そこには今回触れません:bow_tone1:

#### パスパラメータの設定
リソースのアクション→リソースの作成
<img width="1112" alt="pathparameter.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/d521e5f9-e9ee-c143-ae66-d1a00ede449b.png">

#### メソッドの設定(GET)
リソースのアクション→メソッドの作成
<img width="1114" alt="method.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/8ee067eb-d8be-293b-2290-48d5d8ff4390.png">

※ **Lambda プロキシ統合** はAPIGatewayに対するリクエストの情報をよしなにまとめてLambdaに渡してくれるの非常に便利です！！！

#### メソッド作成後
<img width="1097" alt="method_2.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/02d98066-1dc3-f1d0-9fe0-82ed2f4e0e32.png">

# Lambda

```python:handler.py
import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

DYNAMO_TABLE_NAME = 'hoge-dynamodb'

def hoge(event, context):
    path_id = event['pathParameters']['Id']

    # DBConnection
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(DYNAMO_TABLE_NAME)

    partition_key = {"Id": path_id}
    res = table.get_item(Key=partition_key)
    item = res["Item"]
    result = {
        "statusCode": 302,
        "headers": {
            "Location": item['url']
        },
        "body": ''
    }
    return result
```

※ **Lambda プロキシ統合** を設定した場合はlambdaからのレスポンス形式に注意が必要です :warning: 


# DynamoDB
#### 新規テーブル作成
<img width="905" alt="dynamodb.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/0d017803-7549-66f6-d33b-07c59e92ea72.png">

#### 項目の追加
<img width="926" alt="dynamodb-item.png" src="https://qiita-image-store.s3.amazonaws.com/0/61433/c0e11cfc-5052-13f3-f472-a4c909e1fba8.png">


# Serverless設定
```yml:serverless.yml
service: redirect
frameworkVersion: ">=1.1.0 <2.0.0"

custom:
  pythonRequirements:
    dockerizePip: true

provider:
  name: aws
  runtime: python3.6
  stage: dev
  region: ap-northeast-1
  profile: hoge-profile
  environment:
    STAGE: ${self:provider.stage}
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:*
      Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/*"

functions:
  redirect:
    handler: handler.hoge
    events:
      - http:
          method: get
          path: /{Id}
          integration: lambda-proxy

resources:
  Resources:
    RedirectDynamoDbTable:
      Type: AWS::DynamoDB::Table
      DeletionPolicy: Retain
      Properties:
        TableName: hoge-dynamodb
        AttributeDefinitions:
          -
            AttributeName: Id
            AttributeType: S
        KeySchema:
          -
            AttributeName: Id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
```

# デプロイ
```sh:
$ sls deploy -v
```

# 確認
APIGateWayにデプロイされたエンドポイントにpathパラメータをDynamoDBに挿入した `hogepath` を付与してアクセスします。
https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hogepath

無事にリダイレクトされたら成功です:confetti_ball:

# 実行環境
macOS Mojave 10.1４
serverless 1.35.1
npm 6.5.0

# ハマったポイント
ServerlessでDynamoDBのキャパシティユニットを設定しなくてもデフォルト値が入るだろうと記載しないでデプロイしたらCloudFormationのエラーにハマって一日潰しました・・・:sob: