API GatewayとLambdaを使ってクエリ文字列から、DynamoDBにデータの挿入、クエリ、データ削除を行う

本日はクエリ文字列のURLを使用してDynamoDBのデータ挿入、クエリ、行削除を行うフローを構築しました。
目次は以下となります。

<dl>
  <dt>１．Lambdaの構築</dt>
  <dd>１．１．DynamoDBテーブルの作成</dd>
  <dd>１．２．DynamoDBへデータ挿入</dd>
  <dd>１．３．DynamoDBのクエリを実行</dd>
  <dd>１．４．DynamoDBの行削除</dd>
<dt>２．API gatewayの構築</dt>
</dl>


# １．Lambdaの構築

今回の構築では、ユーザ、プログラミング言語、メモを登録するDyanamoDBを作成し、Lambdaで挿入、クエリ、行削除を行うことを想定しています。

### １．１．DynamoDBへデータ挿入

せっかくなので、テーブルを作成するLambdaの構築も行いました。


```
import json
import boto3
def lambda_handler(event, context):
    client = boto3.client('dynamodb', region_name='us-east-1')
    try:
        resp = client.create_table(
            TableName="Programming",

 #ハッシュキーはユーザ、レンジキーは言語にします。
            KeySchema=[
                {
                    "AttributeName": "user",
                    "KeyType": "HASH"
                },
                {
                    "AttributeName": "lang",
                    "KeyType": "RANGE"
                }
            ],

#それぞれのキーは文字列で登録します。
            AttributeDefinitions=[
                {
                    "AttributeName": "user",
                    "AttributeType": "S"
                },
                {
                    "AttributeName": "lang",
                    "AttributeType": "S"
                }
            ],

#キャパシティユニットはそれぞれ1に設定
            ProvisionedThroughput={
                "ReadCapacityUnits": 1,
                "WriteCapacityUnits": 1
            }
        )
        print("Table created successfully!")

#tryの中でエラーが発生した場合の処理
    except Exception as e:
        print("Error creating table:")
        print(e)
```

上記コードのLambdaの実行でDynamoDBテーブルが作成されました。

![スクリーンショット 2023-02-18 131036.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/17170eb8-1df4-d99b-7ed8-03828e3fa271.png)

### １．２．DynamoDBへデータ挿入

それではデータの挿入を行うLambdaを作成していきましょう。
Lambdaの作成と必要なIAMロールを付与した後コードタブにて下記コードを設定しました。
Lambdaにて下記コードをテストしてみます。

```
import json
import boto3

def lambda_handler(event, context):
    # TODO implement
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    table = dynamodb.Table('Programming')

    with table.batch_writer() as batch:
        batch.put_item(Item={"user": "Tom", "lang": "Python",
            "memo": "Pythonは1991年にグイド・ヴァン・ロッサムにより開発された"})
    
    return {
        'statusCode': 200,
        'body': json.dumps('insert success')
    }
```

挿入されました。
![スクリーンショット 2023-02-19 015343.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/eeb72d89-19c1-a544-b84d-29450834cc56.png)

次はAPIGatewayから送られてきたデータを挿入するようにコードを修正します。
どのようにデータが送られてくるかはLambdaのテストタブにて「テンプレート-オプション」でAPIGatewayを選択することで確認できます。
![スクリーンショット 2023-02-19 015751.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/4a4d1034-f18d-b7f4-c580-94033879f9eb.png)
![スクリーンショット 2023-02-19 015858.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/d4f353df-560c-25d8-f6fe-2b21eba033e2.png)
上記の「"queryStringParameters"」にクエリの情報が入っているので下記のようにコードをなおします。

クエリ文字列は「URL?url_name=文字列&url_input_lang=文字列&url_input_text=文字列」のように3つ送られてくることを想定しています。

```
import json
import boto3

def lambda_handler(event, context):
    # TODO implement
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    table = dynamodb.Table('Programming')

    name = event["queryStringParameters"]["url_name"]
    input_lang = event["queryStringParameters"]["url_input_lang"]
    input_text = event["queryStringParameters"]["url_input_text"]
    
    with table.batch_writer() as batch:
        batch.put_item(Item={"user": name, "lang": input_lang,
            "memo": input_text})
    
    return {
        'statusCode': 200,
        'body': json.dumps('insert success')
    }
```

上記コードに修正後、テストのイベントJSONのqueryStringParametersを下記のようにして「テスト」をクリックします。

```
  "queryStringParameters": {
    "url_name": "Bob",
    "url_input_lang": "java",
    "url_input_text": "1996年にサン・マイクロシステムズによって市場リリース"
  },
```

追加されました。
![スクリーンショット 2023-02-19 020414.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/d281869a-d61d-018a-b6d7-f042f295bbfc.png)


### １．３．DynamoDBのクエリを実行

コードは下記になります。ブラウザにクエリ結果を表示したいので、JSON形式でreturnされるよう設定しています。
ユーザ名(url_name)がクエリ文字列で送られるとクエリが実行されることを想定しています。

```
import json
import boto3
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    table = dynamodb.Table('Programming')
    
    name = event["queryStringParameters"]["url_name"]
    resp = table.query(KeyConditionExpression=Key('user').eq(name))
    
    print("The query returned the following items:")
    for item in resp['Items']:
        print(item)

#文字列を返す。json.dumpsでは日本語は文字化けをするため第二引数を「ensure_ascii=False」にすることで文字化けを回避。
    return {
        'statusCode': 200,
        'body': json.dumps(resp['Items'], ensure_ascii=False),
        'headers': {}
    }
```
上記コードでテストしてみます。
テーブルの状態は先ほどのままでBobユーザでテストをしてみて、成功しました。

![スクリーンショット 2023-02-19 022704.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/f450156d-f108-9fdc-724b-ee9a46bee97f.png)


### １．４．DynamoDBの行削除

これまでと同様クエリ文字列にてurl_name、url_langでデータが送られることを想定しています。
ハッシュキーとレンジキーを設定しているので実行するには両方指定する必要があります。
```
import boto3

def lambda_handler(event, context):
  
  dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
  table = dynamodb.Table('Programming')
  
  name = event["queryStringParameters"]["url_name"]
  lang = event["queryStringParameters"]["url_lang"]
  
  response = table.delete_item(
  Key={
    'user': name,
    'lang': lang
  }
)
```
テーブルは先ほどの状態のままなので、BobとJavaを入力しテストを実行します。

```
  "queryStringParameters": {
    "url_name": "Bob",
    "url_lang": "java"
  },
```
成功して削除されていることを確認。

![スクリーンショット 2023-02-19 023813.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/d4a5391c-9201-6cd6-a16e-b98511dec90d.png)

次はAPIGatewayを設定していきます。

### ２．API gatewayの構築


APIを作成し、「アクション」からリソースとメソッドを設定していきます。
まずは、リソース作成にてLambdaプロキシ統合を使用し、該当のLambda関数を入力します。
![スクリーンショット 2023-02-19 224645.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/52293ac8-4a15-7e75-7605-71aa88746c12.png)

「メソッドの作成」にてputメソッドを作成後、「メソッドリクエスト」からURLクエリ文字列パラメータを設定します。
![スクリーンショット 2023-02-19 225058.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/654f19fd-4b35-a4a6-b76a-4ee920f57083.png)

同じ要領でqueryとdeleteのリソースとメソッドも作成します。
3つとも作成したらアクションからAPIのデプロイを選択します。
デプロイすると下記のように呼び出しURLが作成されます。
![スクリーンショット 2023-02-19 230940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/540c48ca-6150-3b06-9b21-a340e7a589c1.png)

### テスト

それではinsert（挿入）,query（クエリ）,delete（行削除）をやっていきましょう。
まずは挿入からです。呼び出しURLの後ろに下記を付けてブラウザへ入力します。
・[呼び出しURL]/insert?url_name=Tom&url_input_lang=Javascript&url_input_text=Javaと似た名称を持つが、異なるプログラミング言語である

![スクリーンショット 2023-02-19 231622.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/770925ae-6f2f-d787-e22d-d5da6c855f04.png)

項目が作成されました。
あと２つくらい適当に項目を作成します。

・[呼び出しURL]/insert?url_name=近藤&url_input_lang=Java&url_input_text=1996年にサン・マイクロシステムズによって市場リリースされた
・[呼び出しURL]/insert?url_name=Tom&url_input_lang=Ruby&url_input_text="Personal Home Page Tools" （短縮されて "PHP Tools" と呼ばれていた）を起源とする

![スクリーンショット 2023-02-19 233423.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/a19ab09b-c6a9-95dd-0ad0-045dec7b52de.png)


次に下記を入力し、クエリが行われるかテストします。
[呼び出しURL]/query?url_name=Tom


![スクリーンショット 2023-02-19 233548.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/aea51c67-0fea-d5f9-5abb-4a340306bbb7.png)

ブラウザにLambdaで設定した通りに表示されました。
続いて行削除を行っていきます。
[呼び出しURL]/delete?url_name=Tom&url_lang=Ruby

![スクリーンショット 2023-02-19 233701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/caebda98-fcc4-5042-8bf4-4e05244611d1.png)

指定したものが削除されました。
全て想定通りいきましたので、本記事はこれで終了といたします。