

# チュートリアル: Lambda と DynamoDB を使用して CRUD HTTP API を作成する
<a name="http-api-dynamo-db"></a>

このチュートリアルでは、DynamoDB テーブルから項目を作成、読み取り、更新、削除するサーバーレス API を作成します。DynamoDB は、高速で予測可能なパフォーマンスとシームレスな拡張性を特長とするフルマネージド NoSQL データベースサービスです。このチュートリアルの所要時間は約 30 分で、[AWS の無料利用枠](https://aws.amazon.com/free/)内で実行できます。

まず、[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) コンソールを使用して DynamoDB テーブルを作成します。次に、AWS Lambda コンソールを使用して [Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 関数を作成します。次に、API Gateway コンソールを使用して HTTP API を作成します。最後に、API をテストします。

HTTP API を呼び出すと、API Gateway はリクエストを Lambda 関数にルーティングします。Lambda 関数は DynamoDB と対話し、API ゲートウェイにレスポンスを返します。それから API Gateway はレスポンスを返します。

![\[このチュートリアルで作成する HTTP API の概要。\]](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/images/ddb-crud.png)


このエクササイズを完了するには、AWS アカウントと、コンソールへのアクセス権がある AWS Identity and Access Management ユーザーが必要です。詳細については、「[API Gateway を使用するようにセットアップする](setting-up.md)」を参照してください。

このチュートリアルでは、 を使用しますAWS マネジメントコンソール この API とすべての関連リソースを作成する AWS SAM テンプレートについては、[samples/http-dynamo-tutorial.zip](samples/http-dynamo-tutorial.zip) を参照してください。

**Topics**
+ [ステップ 1: DynamoDB テーブルを作成する](#http-api-dynamo-db-create-table)
+ [ステップ 2: Lambda 関数を作成する](#http-api-dynamo-db-create-function)
+ [ステップ 3: HTTP API を作成する](#http-api-dynamo-db-create-api)
+ [ステップ 4: ルートを作成する](#http-api-dynamo-db-create-routes)
+ [ステップ 5: 統合を作成する](#http-api-dynamo-db-create-integration)
+ [ステップ 6: 統合をルートにアタッチする](#http-api-dynamo-db-attach-integrations)
+ [ステップ 7: API をテストする](#http-api-dynamo-db-invoke-api)
+ [ステップ 8: クリーンアップする](#http-api-dynamo-db-cleanup)
+ [次のステップ: AWS SAM または CloudFormation を使用して自動化する](#http-api-dynamo-db-next-steps)

## ステップ 1: DynamoDB テーブルを作成する
<a name="http-api-dynamo-db-create-table"></a>

[DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) テーブルを使用して API のデータを保存します。

各項目には一意の ID があり、これをテーブルの[パーティションキー](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey)として使用します。

**DynamoDB テーブルを作成するには**

1. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/) で DynamoDB コンソールを開きます。

1. [**Create table**] を選択します。

1. **[テーブル名]** に **http-crud-tutorial-items** と入力します。

1. **[パーティションキー]** に **id** と入力します。

1. [**Create table (テーブルの作成)**] を選択します。

## ステップ 2: Lambda 関数を作成する
<a name="http-api-dynamo-db-create-function"></a>

API のバックエンドに [Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 関数を作成します。この Lambda 関数は、DynamoDB から項目を作成、読み取り、更新、および削除します。この関数は、[API ゲートウェイのイベントを使用して](http-api-develop-integrations-lambda.md#http-api-develop-integrations-lambda.proxy-format) DynamoDB との対話方法を決定します。わかりやすくするために、このチュートリアルでは 1 つの Lambda 関数を使用しますが、ルートごとに個別の関数を作成するのがベストプラクティスです。詳細については、「[The Lambda monolith](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/monolith)」(Lambda モノリス) を参照してください。

**Lambda 関数を作成するには**

1. Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda)) にサインインします。

1. [**関数の作成**] を選択します。

1. [**関数名**] に「**http-crud-tutorial-function**」と入力します。

1. **[ランタイム]** で、サポートされている最新の **Node.js** または **Python** ランタイムのいずれかを選択します。

1. [**アクセス許可**] で [**デフォルトの実行ロールの変更**] を選択します。

1. [**Create a new role from AWS policy templates**] (AWS ポリシーテンプレートから新しいロールを作成) を選択します。

1. [**ロール名**] に「**http-crud-tutorial-role**」と入力します。

1. [**ポリシーテンプレート**] では、[**Simple microservice permissions**] を選択します。このポリシーは、Lambda 関数に DynamoDB と対話するためのアクセス許可を付与します。
**注記**  
このチュートリアルでは、わかりやすくするために管理ポリシーを使用しますが、独自の IAM ポリシーを作成して、必要な最小限のアクセス許可を付与するのがベストプラクティスです。

1. [**関数の作成**] を選択してください。

1. コンソールのコードエディタで Lambda 関数を開き、その内容を次のコードに置き換えます。[**デプロイ**] を選択して、関数を更新します。

------
#### [ Node.js ]

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  DynamoDBDocumentClient,
  ScanCommand,
  PutCommand,
  GetCommand,
  DeleteCommand,
} from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({});

const dynamo = DynamoDBDocumentClient.from(client);

const tableName = "http-crud-tutorial-items";

export const handler = async (event, context) => {
  let body;
  let statusCode = 200;
  const headers = {
    "Content-Type": "application/json",
  };

  try {
    switch (event.routeKey) {
      case "DELETE /items/{id}":
        await dynamo.send(
          new DeleteCommand({
            TableName: tableName,
            Key: {
              id: event.pathParameters.id,
            },
          })
        );
        body = `Deleted item ${event.pathParameters.id}`;
        break;
      case "GET /items/{id}":
        body = await dynamo.send(
          new GetCommand({
            TableName: tableName,
            Key: {
              id: event.pathParameters.id,
            },
          })
        );
        body = body.Item;
        break;
      case "GET /items":
        body = await dynamo.send(
          new ScanCommand({ TableName: tableName })
        );
        body = body.Items;
        break;
      case "PUT /items":
        let requestJSON = JSON.parse(event.body);
        await dynamo.send(
          new PutCommand({
            TableName: tableName,
            Item: {
              id: requestJSON.id,
              price: requestJSON.price,
              name: requestJSON.name,
            },
          })
        );
        body = `Put item ${requestJSON.id}`;
        break;
      default:
        throw new Error(`Unsupported route: "${event.routeKey}"`);
    }
  } catch (err) {
    statusCode = 400;
    body = err.message;
  } finally {
    body = JSON.stringify(body);
  }

  return {
    statusCode,
    body,
    headers,
  };
};
```

------
#### [ Python ]

```
import json
import boto3
from decimal import Decimal

client = boto3.client('dynamodb')
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table('http-crud-tutorial-items')
tableName = 'http-crud-tutorial-items'


def lambda_handler(event, context):
    print(event)
    body = {}
    statusCode = 200
    headers = {
        "Content-Type": "application/json"
    }

    try:
        if event['routeKey'] == "DELETE /items/{id}":
            table.delete_item(
                Key={'id': event['pathParameters']['id']})
            body = 'Deleted item ' + event['pathParameters']['id']
        elif event['routeKey'] == "GET /items/{id}":
            body = table.get_item(
                Key={'id': event['pathParameters']['id']})
            body = body["Item"]
            responseBody = [
                {'price': float(body['price']), 'id': body['id'], 'name': body['name']}]
            body = responseBody
        elif event['routeKey'] == "GET /items":
            body = table.scan()
            body = body["Items"]
            print("ITEMS----")
            print(body)
            responseBody = []
            for items in body:
                responseItems = [
                    {'price': float(items['price']), 'id': items['id'], 'name': items['name']}]
                responseBody.append(responseItems)
            body = responseBody
        elif event['routeKey'] == "PUT /items":
            requestJSON = json.loads(event['body'])
            table.put_item(
                Item={
                    'id': requestJSON['id'],
                    'price': Decimal(str(requestJSON['price'])),
                    'name': requestJSON['name']
                })
            body = 'Put item ' + requestJSON['id']
    except KeyError:
        statusCode = 400
        body = 'Unsupported route: ' + event['routeKey']
    body = json.dumps(body)
    res = {
        "statusCode": statusCode,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": body
    }
    return res
```

------

## ステップ 3: HTTP API を作成する
<a name="http-api-dynamo-db-create-api"></a>

HTTP API は、Lambda 関数の HTTP エンドポイントを提供します。このステップでは、空の API を作成します。次のステップでは、API と Lambda 関数を接続するようにルートと統合を設定します。



**HTTP API を作成するには**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway) で API Gateway コンソールにサインインします。

1. [**API を作成**] を選択し、[**HTTP API**] で [**構築**] を選択します。

1. [**API 名**] に「**http-crud-tutorial-api**」と入力します。

1. **[IP アドレスの種類]** には **[IPv4]** を選択します。

1. [**次へ**] を選択します。

1. [**ルートの設定**] で、[**次へ**] を選択してルートの作成をスキップします。ルートは後で作成します。

1. API Gateway によって作成されるステージを確認し、[**次へ**] をクリックします。

1. [**Create**] を選択します。

## ステップ 4: ルートを作成する
<a name="http-api-dynamo-db-create-routes"></a>

ルートは、着信 API リクエストをバックエンドリソースに送信する方法です。ルートは、HTTP メソッドとリソースパスという 2 つの部分で構成されます (例: `GET /items`)。この例の API では、次の 4 つのルートを作成します。
+ `GET /items/{id}`
+ `GET /items`
+ `PUT /items`
+ `DELETE /items/{id}`

**ルートを作成するには**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway) で API Gateway コンソールにサインインします。

1. API を選択します。

1. [**ルート**] をクリックします。

1. [**Create**] を選択します。

1. [**Method**] (メソッド) で、[**GET**] を選択します。

1. パスには、「**/items/\$1id\$1**」と入力します。パスの末尾にある `{id}` は、クライアントがリクエストを行うときに API Gateway がリクエストパスから取得するパスパラメータです。

1. [**Create**] を選択します。

1. `GET /items`、`DELETE /items/{id}`、および `PUT /items` について、ステップ 4～7 を繰り返します 。

![\[API には GET /items、GET /items/{id}、DELETE /items/{id}、および PUT /items 用のルートがあります。\]](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/images/ddb-create-routes.png)


## ステップ 5: 統合を作成する
<a name="http-api-dynamo-db-create-integration"></a>

ルートをバックエンドリソースに接続するための統合を作成します。この API の例では、すべてのルートに使用する 1 つの Lambda 統合を作成します。

**統合を作成するには**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway) で API Gateway コンソールにサインインします。

1. API を選択します。

1. [**統合**] を選択します。

1. [**統合を管理**] を選択し、[**作成**] をクリックします。

1. [**この統合をルートにアタッチする**] はスキップします。これは、後の手順で完了します。

1. [**統合タイプ**] で、[**Lambda 関数**] を選択します。

1. [**Lambda 関数**] に「**http-crud-tutorial-function**」と入力します。

1. [**Create**] を選択します。

## ステップ 6: 統合をルートにアタッチする
<a name="http-api-dynamo-db-attach-integrations"></a>

この API の例では、すべてのルートで同じ Lambda 統合を使用します。統合を API のすべてのルートにアタッチすると、クライアントがいずれかのルートを呼び出すと Lambda 関数が呼び出されます。



**統合をルートにアタッチするには**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway) で API Gateway コンソールにサインインします。

1. API を選択します。

1. [**統合**] を選択します。

1. ルートを選択します。

1. [**既存の統合を選択する**] で、[**http-crud-tutorial-function**] を選択します。

1. [**統合をアタッチする**] を選択します。

1. すべてのルートについて、ステップ 4～6 を繰り返します。

すべてのルートが、AWS Lambda 統合がアタッチされていることを示します。

![\[コンソールでは、すべてのルートに AWS Lambda が表示され、統合がアタッチされていることを示します。\]](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/images/ddb-attach-integrations.png)


ルートと統合を持つ HTTP API ができたので、API をテストできます。

## ステップ 7: API をテストする
<a name="http-api-dynamo-db-invoke-api"></a>

API が動作していることを確認するには、[curl](https://curl.se) を使用します。

**API を呼び出すための URL を取得するには**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway) で API Gateway コンソールにサインインします。

1. API を選択します。

1. API の呼び出し URL を書き留めます。URL は、[**詳細**] ページの [**URL を呼び出す**] の下に表示されます。  
![\[APIを作成すると、コンソールに API の呼び出し URL が表示されます。\]](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/images/ddb-invoke-url.png)

1. API の呼び出し URL をコピーします。

   完全な URL は `https://abcdef123.execute-api.us-west-2.amazonaws.com` のように見えます。

**項目の作成または更新**
+ 次のコマンドを使用して、項目を作成または更新します。コマンドには、項目の ID、料金、名前を含むリクエスト本文が含まれます。

  ```
  curl -X "PUT" -H "Content-Type: application/json" -d "{\"id\": \"123\", \"price\": 12345, \"name\": \"myitem\"}" https://abcdef123.execute-api.us-west-2.amazonaws.com/items
  ```

**すべての項目を取得するには**
+ すべての項目を一覧表示するには、次のコマンドを使用します。

  ```
  curl https://abcdef123.execute-api.us-west-2.amazonaws.com/items
  ```

**1 つの項目を取得するには**
+ ID で 1 つの項目を取得するには、次のコマンドを使用します。

  ```
  curl https://abcdef123.execute-api.us-west-2.amazonaws.com/items/123
  ```

**項目を削除するには**

1. 項目を削除するには、次のコマンドを使用します。

   ```
   curl -X "DELETE" https://abcdef123.execute-api.us-west-2.amazonaws.com/items/123
   ```

1. 項目が削除されたことを確認するには、すべての項目を取得します。

   ```
   curl https://abcdef123.execute-api.us-west-2.amazonaws.com/items
   ```

## ステップ 8: クリーンアップする
<a name="http-api-dynamo-db-cleanup"></a>

不要なコストを回避するには、このエクササイズで作成したリソースを削除します。次の手順では、HTTP API、Lambda 関数、および関連リソースを削除します。

**DynamoDB テーブルを削除するには**

1. DynamoDB コンソール ([https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)) を開きます。

1. テーブルを選択します。

1. [**テーブルの削除**] を選択します。

1. 選択を確認して、[**削除**] をクリックします。

**HTTP API を削除するには**

1. [https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway) で API Gateway コンソールにサインインします。

1. [** API **] ページで、API を選択します。[** Actions**] を選択して、[**Delete**] を選択します。

1. [**削除**] を選択します。

**Lambda 関数を削除するには**

1. Lambda コンソール ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda)) にサインインします。

1. [** 関数 **] ページで、関数を選択します。[** Actions**] を選択して、[**Delete**] を選択します。

1. [**削除**] を選択します。

**Lambda 関数のロググループを削除するには**

1. Amazon CloudWatch コンソールで、[[ ロググループページ](https://console.aws.amazon.com/cloudwatch/home#logs:)]を開きます。

1. [**ロググループ**] ページで、関数のロググループ (`/aws/lambda/http-crud-tutorial-function`) を選択します。[**Actions**] (アクション) を選択してから、[**Delete log group**] (ロググループの削除) を選択します。

1. [**削除**] を選択します。

**Lambda 関数の実行ロールを削除するには**

1. AWS Identity and Access Management コンソールの [[Roles](https://console.aws.amazon.com/iam/home?#/roles)] (ロール) ページを開きます。

1. 関数のロールを選択します (例: `http-crud-tutorial-role`)。

1. [**ロールの削除**] を選択します。

1. [**はい、削除します**] を選択します。

## 次のステップ: AWS SAM または CloudFormation を使用して自動化する
<a name="http-api-dynamo-db-next-steps"></a>

CloudFormation または AWS SAM を使用して、AWS リソースの作成とクリーンアップを自動化できます。このチュートリアルのサンプル AWS SAM テンプレートについては、[samples/http-dynamo-tutorial.zip](samples/http-dynamo-tutorial.zip) を参照してください。

CloudFormation テンプレートの例については、「[サンプル CloudFormation テンプレート](https://github.com/awsdocs/amazon-api-gateway-developer-guide/tree/main/cloudformation-templates)」を参照してください。