0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【CDK】 色んな言語でCRUD API作る【TypeScript】

0
Last updated at Posted at 2022-07-17

この記事について

AWS CDKv2でCRUD操作ができるAPIを作る
今回はTypeScriptを使う

アプリの構成図

infra (1).png

API Gateway + Lambda + DynamoDBでTODOオブジェクトのCRUD操作ができるAPIを作る

プロジェクト初期化

CLIのインストール

まずはCDK CLIをインストールする

npm install -g aws-cdk
cdk --version

バージョンが表示されればOK

CDK Toolkitのデプロイ

初回のみCDKを利用する際に必要となるファイル群のデプロイが必要

cdk bootstrap aws://${ACCOUNT}/${REGION}

以下のように表示されればOK

✅  Environment aws://${ACCOUNT}/${REGION} bootstrapped.

※異なるアカウント、リージョンでCDKを利用する場合はまたこの作業が必要になる

プロジェクト初期化

適当なディレクトリで↓を実行

cdk init app --language typescript

こんな感じでプロジェクトが初期化される
スクリーンショット 2022-07-01 153603.jpg

実装

CDKのコードを書く

スタックの実装

/lib以下のファイルにスタック(CDKでデプロイするリソース群の単位)を実装する

/lib/todoapp-ts-stack.ts
import { RemovalPolicy, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda-nodejs";
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import * as logs from "aws-cdk-lib/aws-logs";
import * as apigateway from "aws-cdk-lib/aws-apigateway";

export class TodoappTsStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // DynamoDB
    const todosTable = new dynamodb.Table(this, "TodosTable", {
      partitionKey: { name: "id", type: dynamodb.AttributeType.STRING },
      tableName: "todoapp-ts-todos-table",
      removalPolicy: RemovalPolicy.DESTROY,
    });

    // Lambda
    const todoFunction = new lambda.NodejsFunction(this, "TodoFunction", {
      entry: "src/main.ts", // Lambdaのソースコードのエントリポイント
      handler: "handler", // "entry"で指定したファイルのexportしている関数名
      environment: {
        TODOS_TABLE_NAME: todosTable.tableName,
      },
      functionName: "todoapp-ts-function",
    });
    // LambdaにDynamoDBのCRUD操作権限を付与
    todoFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          "dynamodb:Scan",
          "dynamodb:PutItem",
          "dynamodb:UpdateItem",
          "dynamodb:DeleteItem",
        ],
        resources: [todosTable.tableArn],
      })
    );

    // LogGroup
    new logs.LogGroup(this, "TodoFunctionLogs", {
      logGroupName: "/aws/lambda/" + todoFunction.functionName,
      removalPolicy: RemovalPolicy.DESTROY,
    });

    // API Gateway
    const api = new apigateway.RestApi(this, "TodoApi", {
      restApiName: "todoapp-ts-todo-api",
      defaultCorsPreflightOptions: {
        allowOrigins: apigateway.Cors.ALL_ORIGINS,
        allowMethods: apigateway.Cors.ALL_METHODS,
        allowHeaders: apigateway.Cors.DEFAULT_HEADERS,
        statusCode: 200,
      },
    });
    const integration = new apigateway.LambdaIntegration(todoFunction);

    // /todos
    const todosResource = api.root.addResource("todos");
    todosResource.addMethod("GET", integration);
    todosResource.addMethod("POST", integration);

    // /todos/{id}
    const todoIdResource = todosResource.addResource("{id}");
    todoIdResource.addMethod("PUT", integration);
    todoIdResource.addMethod("DELETE", integration);
  }
}

Lambdaについて

Lambdaの作成にはaws-lambda-nodejsを使っている

このモジュールを使うとTypeScriptのコードをjavascriptに変換する作業(トランスパイル)をCDKのデプロイ時によしなにやってくれる

ちなみにPythonGoにも同様のモジュールが用意されているもののまだアルファ版
javaと.NETにはないっぽい

Lambdaのコード実装

こちらのサンプルコードを参照
今回はexpressでルーティングを、serverless-expressでAPI Gatewayのイベントとの結合を実装してみた

デプロイ

↓を実行

cdk deploy TodoappTsStack

ちなみに、スタック名などは/bin/todoapp-ts.tsで指定している

/bin/todoapp-ts.ts
#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { TodoappTsStack } from "../lib/todoapp-ts-stack";

const app = new cdk.App();
new TodoappTsStack(app, "TodoappTsStack"); // ここの"TodoappTsStack"を指定する

/libにスタックを追加した場合はこのファイル内でインスタンス生成してあげればOK

動作確認

デプロイが完了したら以下のスクリプトを実行

#!/bin/bash

ENDPOINT="API Gatewayのエンドポイント"

RESPONSE=$(curl "${ENDPOINT}/todos" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"message":"post todo"}' \
  -w"\n")
echo ${RESPONSE}
TODO_ID=$(echo ${RESPONSE} | jq .data.todo.id -r)

curl "${ENDPOINT}/todos" \
  -w"\n"

curl "${ENDPOINT}/todos/${TODO_ID}" \
  -X PUT \
  -H "Content-Type: application/json" \
  -d '{"message":"put todo"}' \
  -w"\n"

curl "${ENDPOINT}/todos/${TODO_ID}" \
  -X DELETE \
  -w"\n"

こんな感じで出力されていれば成功

{"message":"Post todo succeed.","data":{"todo":{"id":"39593ece-2bc7-4456-b52f-3265494b8331","message":"post todo"}}}
{"message":"Get todos succeed.","data":{"todos":[{"id":"39593ece-2bc7-4456-b52f-3265494b8331","message":"post todo"}]}}
{"message":"Put todo succeed.","data":{"todo":{"id":"39593ece-2bc7-4456-b52f-3265494b8331","message":"put todo"}}}
{"message":"Delete todo succeed."}

感想

TypeScriptの静的型付けによってCloudFormationをプログラミング言語で書けるCDKの恩恵を最大限に受けられた
また、Webアプリの場合はクライアントもTypeScriptで書くことが多いので言語を統一できるのもGood
LambdaのコードをTypeScriptで書いた場合のトランスパイルについてもそれ用のモジュールがあるので全く問題ない
CDKのサンプルコードや記事なども他の言語に比べて多いのもうれしい

総じて使い勝手は良好なのでWebアプリのプロジェクトならTypeScriptが丸いと思う

参考リンク

サンプルコード
https://github.com/tetsu0000/todoapp-ts

AWS公式ドキュメント
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/home.html
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html

aws-sdk-v3の公式ドキュメント
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html

serverless-express
https://github.com/vendia/serverless-express

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?