5
5

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 1 year has passed since last update.

API Gateway、Lambda(Node.js)、DynamoDB を使ったAPIの作り方

Last updated at Posted at 2022-07-07

API Gateway、Lambda、DynamoDB を使ったAPIの作り方を備忘録も兼ねて記載します。
プログラム言語にはNode.jsを利用します。

システム構成

システム構成は以下のようになります。
AWS.png

システム概要

今回はサンプルとして、DynamoDBに格納されているイベント情報をPOSTリクエストで取得して、Jsonを出力するAPIを作ります。

1. DynamoDBにテーブルを作成

最初にイベント情報を格納するテーブルを作成します。
dynamodb1.png

テーブル名は event、パーティションキーは eid とします。
入力し終わったらページ下部の「テーブルの作成」をクリックします。
dynamodb2.png

下図のようになれば、テーブル完成です。
dynamodb3.png

2. DynamoDBにサンプルデータを登録

作成した eventテーブルにサンプルデータを登録します。
作成した event をクリックしてください。
dynamodb4.png

「項目を作成」をクリックします。
dynamodb5.png

フォームでも良いのですが、今回はJSONを選択します。
dynamodb6.png

以下のようにJsonデータを入力して、「項目の作成」をクリックしてください。
dynamodb7.png

「項目の探索」から以下のようにスキャンを実行して、データが表示できれば登録は成功です。
dynamodb8.png

3. IAMロールの作成

LambdaからDynamoDBにアクセスする為のIAMロールを作成します。

IAMの画面に遷移し、「ロールを作成」をクリック
iam1a.png

信頼されたエンティティタイプに「AWSのサービス」を選び、ユースケースに「Lambda」を選択して 次へをクリック
iam2.png

検索フォームに「dynamodb」と入力して表示を絞り込み、ポリシーから AmazonDynamoDBFullAccessAmazonLambdaDynamoDBExecutionRole を選択して次へクリック
iam3.png

任意の名称(ここでは「LambdaAccess」とする)を入力して、ページ下部のロールを作成をクリック
iam4.png

ロール一覧画面で、作成したロールが表示されていればOKです。
iam5.png

4. Node.js をインストール

今回はNode.js で Lambda関数を作っていきます。その為にローカル環境に Node.js をインストールします。
環境は Windows 10 home です。
こちらの記事が分かりやすかったので、こちらを見ながらNode.jsをインストールしましょう。

5. ローカルのNode.jsでLambda用の関数を作成

ローカルのNode.jsでLambdaにアップロードする関数を作っていきます。
関数の仕様としては、先につくっておいたDynamoDB(eventテーブル)をよみこんでJsonレスポンスを返却するという単純なものです。
まずは任意のディレクトリ(ここではCドライブ直下のlambda\apiディレクトリ)に移動しましょう

cd C:\lambda\api  ### ディレクトリを移動

ここで npm の初期化と必要なモジュールをインストールします。

C:\lambda\api> npm init  ### 初期化します( package.jsonファイルが作成される)

npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (api)  ### そのままEnter
version: (1.0.0)  ### そのままEnter
description:  ### そのままEnter
entry point: (index.js)  ### そのままEnter
test command:  ### そのままEnter
git repository:  ### そのままEnter
keywords:  ### そのままEnter
author:  ### そのままEnter
license: (ISC) MIT  ### MITライセンス
About to write to C:\lambda\api\package.json:

{
  "name": "api",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}

Is this OK? (yes)  ### そのままEnter
npm notice
npm notice New minor version of npm available! 8.11.0 -> 8.13.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.13.2
npm notice Run npm install -g npm@8.13.2 to update!
npm notice

必要なライブラリをインストール

cd C:\lambda\api> npm install moment-timezone  ### 時刻関連のライブラリをインストール

すると、ディレクトリが以下のようになります。

├─package.json
├─package-lock.json
└─node_modules
    ├─moment  ### 自動でインストールされるライブラリ
    └─moment-timezone  ### インストールしたライブラリ

DynamoDBの「eventテーブル」を操作するロジックである event.jsmodules ディレクトリに置きます。
package.jsonがあるディレクトリに移動して以下コマンドを実行してください。

mkdir modules
cd modules
vi event.js   ### エディタは任意のものを使ってください(ここではviエディタを利用)

event.js には以下を記述してください。

const aws = require("aws-sdk");
const dynamoDB = new aws.DynamoDB.DocumentClient({ region: "ap-northeast-1" });

/**
 * --------------------------------------------------------
 * テーブルの定義(将来用に環境毎にテーブルを分ける)
 * --------------------------------------------------------
 */
const DB_Event = {
    prd:'event',    //今回作ったDynamoDBテーブルはこれ
    stg:'stg_event',
    dev:'dev_event'
};

/**
 * --------------------------------------------------------
 * イベント情報の読み込み
 * --------------------------------------------------------
 */
module.exports.evLoad = async(posts) => {
    return new Promise(function (resolve){
        
        let params = {
            TableName: DB_Event[process.env.STAGE], //環境変数でテーブルを選択する(※1)
            Key: {
                'eid':posts.eid
            }
        };
        dynamoDB.get(params, function(err, data){
            if(err){
                console.log("error: " + err)
                resolve({'status': err.message});
            }
            else{
                if(Object.keys(data).length != 0){
                    resolve({'status':'success', 'ev':data.Item});
                }
                else{
                    resolve({'status':'data length error'});
                }
            }
        });
    });
};

次にメインの処理である index.js を作成します。
package.jsonがあるディレクトリに移動して以下コマンドを実行してください。

vi index.js   ### エディタは任意のものを使ってください(ここではviエディタを利用)

index.js には以下を記述してください。

const mods_event = require("./modules/event");
const moment = require("moment-timezone");
moment.tz.setDefault("Asia/Tokyo");

exports.handler = async (event, context, callback) => {

    if (event.action === undefined) {
        console.log('action は必須です');
        callback(null, { 'result': 'no action' });
        return;
    }
    let posts = Object.assign({}, event);
    console.log("posts: " + JSON.stringify(posts));

    //action毎に処理を分岐
    switch(posts.action){
        case 'overview': //イベント概要ページ
            await overview(callback, posts);
            break;
        default:
            break;   
    }
};

/**
 * --------------------------------------------------------
 * イベント概要ページの処理
 * --------------------------------------------------------
 */
 async function overview(callback, posts) {

    //イベント情報の読み込み
    let res = await mods_event.evLoad(posts);
    let ev;
    if (res.status == 'success') {
        ev = Object.assign({}, res.ev);
    }
    else {
        await errorReturn(res, callback);
        return;
    }

    successReturn(callback, ev);
}

/**
 * --------------------------------------------------------
 * OKレスポンス
 * --------------------------------------------------------
 */
 function successReturn(callback, ev) {

    let data = {
        'status': 'success',
        'item': ev
    };

    callback(null, {
        'statusCode': 200,
        "headers": {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*' 
        },
        'body': data
    });
}

/**
 * --------------------------------------------------------
 * NGレスポンス
 * --------------------------------------------------------
 */
async function errorReturn(message, callback) {

    callback(null, {
        'statusCode': 200,
        "headers": {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*' 
        },
        'body': {
            'status': 'error',
            'errorMessage': message
        }
    });
}

これでLambda用の関数(Node.js)に必要なファイルが揃いました。
ディレクトリは以下のようになります。

├─modules
│   └─event.js   ### viで作成したファイル
├─node_modules
│   ├─moment
│   └─moment-timezone
├─index.js   ### viで作成したファイル
├─package.json
└─package-lock.json

続いて、Lambaへアップロードする為に、作成したファイル一式を選択して、圧縮します。
ここでは圧縮したzipファイルを eventFunction.zip とします。
zip.png

6. Lambdaの設定(関数のアップロード)

Lambdaの画面に遷移して、「関数の作成」をクリック。
Lambda1.png

今回は「一から作成」を選んで、任意の関数名(ここではeventFunction)を入力します。
ランタイムは「Node.js」を選択し、実行ロールには、先に作っておいた LambdaAccess を選択します(このロールが無いとDynamoDBアクセス時に access denied エラーになります)
その後にページ下部の「関数の作成」をクリックします。
Lambda2.png

すると、以下のようなレイアウトの画面が表示されますので、アップロード元 の「.zipファイル」をクリックします。
Lambda3.png

以下のダイアログが表示されるので、上記で作成した eventFunction.zip を選択してアップロードします。
Lambda5.png

7. Lambdaの設定(環境変数)

event.js ソースコードにあった (※1) で利用する環境変数を登録します。
今回は本番運用用のLambda関数として登録するので、prd という文字列を登録していきます。
Lambdaの画面から「設定」タブを選択して「編集」をクリックしてください。
Lambda6.png
「環境変数の追加」をクリックしてください。
Lambda7.png
キーに STAGE、値に prd を入力して「保存」をクリックしてください。
これで環境変数の設定は完了です。
Lambda8.png

8. LambdaからDynamoDBに接続してみる

ここまででLambdaとDynamoDBの設定が完了しました。
試しにテストコンソールで Lambdaにアクセスして DynamoDBからデータを取ってきましょう。

「Configure test event」をクリックします。
test1.png

すると以下のようなダイアログが表示されるので、イベント名(ここではeventFunction)とイベントJSON(これがリクエストJSONになる)を入力します。
そして、わかりずらいですが、ダイアログを下にスクロールすると「保存」ボタンがあるので、それをクリックします。
test2.png

その後、作成したイベント名(eventFunction)を選択しておきます。
test3.png

最後に「Test」ボタンをクリックします。以下のようなレスポンスJSONが返ってくれば成功です(DynamoDBからイベント情報を読み取り成功です)
test4.png

9. API Gatewayの設定

API Gateway の画面に移って、「REST API」の「構築」をクリックします。
apig1.png

「新しいAPI」をチェックし、任意のAPI名(ここではeventとします)を入力します。
エンドポイントタイプには「リージョン」を選択して、「APIの作成」をクリックします。
apig2.png

「アクション」メニューから「メソッドの作成」を選択します。
apig3.png

プルダウンメニューから「POST」リクエストを選択します。
apig4.png

POSTの隣の「レ」マークをクリックして反映します
apig5.png

Lambda関数の欄に、先に作成したLambda関数である「eventFunction」を入力して「保存」をクリックします。
apig6.png

Lambda関数を呼び出す権限を聞かれるので「OK」をクリックします。
apig7.png

リクエストとレスポンスの間に入力したLambda関数である「eventFunction」が表示されます。
apig8.png

Lambdaの画面に移っても、eventFunction のフロントに API Gateway が設定されていることが分かります。
apig9.png

実際に疎通させるには、API Gateway をデプロイする必要があります。
アクションメニューから「APIのデプロイ」を選択します。
apig10.png

ステージ名に任意の名称を入力します(今回は本番用のデプロイなので「prd」と入力します)
※prdはURLにも反映されます。
apig11.png

デプロイが完了しました。
「URLの呼び出し」というところに、このAPI Gateway のエンドポイントが表示されます。
このURLを使って API Gateway → Lambda → DynamoDB にアクセスすることが出来るようになりました。
apig12.png

試しにpostmanをつかって実際にAPIにアクセスしてみましょう。
postmanの設定を以下ように
 メソッド:post
 URL:API Gateway のエンドポイント
 リクエストボディ:下記のJSON
を入力して「Send」ボタンをクリックしましょう。
レスポンスにDynamoDBのeventテーブルで登録したイベント情報が返ってきたら成功です。
apig13.png

なお、独自ドメインでアクセスしたい場合には以下の記事を参考にしてみてください。

また、GETでパラメータを取得したい場合には以下の記事が参考になりました。

以上

参考資料

5
5
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
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?