AWS の EC2 に Node.js で作成したサーバーから、DynamoDB にアクセスします。

ここでは以下を実現します。

  1. ローカル PC 上で、Node.js の環境を作ります。
  2. クライアントアプリケーションからローカル PC 上の Node.js サーバーを経由して。AWS DynamoDB にアクセスします。
    • この後の、CognitoやLambdaを使用したアプリケーションでも、ローカルの確認環境として、Node.jsのサーバーを使用します。
  3. AWS EC2 上に、Node.jsのサーバーをアップロードして、EC2 のサーバー環境で動作確認します。

アプリケーションの全体のコードは、以下からダウンロードできます。

PC上のローカル環境を構築

Node.jsのインストール

Node.js のホームページから、Windowsのインストーラをダウンロードして、PCにインストールします。
詳細は、Node.js のホームページを参照してください。
基本的には、インストーラを実行するだけです。
今回このアプリケーションの開発では、node.js は、v4.1.0 を使用しました。

サーバー・プロジェクトの作成

  1. インストールした、Node.js の、Node.js command prompt を起動します。
  2. アプリケーションを作成するディレクトリに移動して、npm init で、プロジェクトを初期化します。
    npm を使用することで、依存するライブラリのインストールを自動化できます。
    1. ここでは、mynote というディレクトリで作成しました。
    2. entry point は、app.js にしました。
    3. 他は、デフォルトのまま enter キーで進みます。
      c:\projects>mkdir mynote
      
      c:\project>cd mynote
      
      c:\projects\mynote>npm init
      This utility will walk you through creating a package.json file.
      It only covers the most common items, and tries to guess sensible defaults.
      
      ・・・ 省略 ・・・
      
      Press ^C at any time to quit.
      name: (mynote)
      
      version: (1.0.0)
      description:
      entry point: (index.js) napp.js
      test command:
      git repository:
      keywords:
      author:
      license: (ISC)
      About to write to c:\projects\mynote\package.json:
      
      {
        "name": "mynote",
        "version": "1.0.0",
        "description": "",
        "main": "app.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1"
        },
        "author": "",
        "license": "ISC"
      }
      
      
      Is this ok? (yes) yes
      				
  3. Node.js アプリケーションのフレームワークは、express を使用しました。
    1. Express のインストールの詳細は、Express のホームページを参照してください。
      1. Express
    2. すでに、npm init しているので、exporess で "destination is not empty, continue?" と聞かれますが、"y" を入力して continue します。
      c:\projects\mynote>npm install express --save
      c:\projects\mynote>cd ..
      c:\projects>express mynote
      destination is not empty, continue? [y/N] y
      y
         … 省略  …
      
         install dependencies:
           > cd mynote && npm install
      
         run the app:
           > SET DEBUG=mynote:* & npm start
      
      
      c:\projects>cd mynote
      c:\projects\mynote>npm install
      				
    3. ここまでで、問題ないか、サーバーを起動してみます。
      c:\projects\mynote>set DEBUG=mynote:* & npm start
      
      > mynote@0.0.0 start c:\projects\mynote
      > node ./bin/www
      
        mynote:server Listening on port 3000 +0ms
      				
      Control + C でサーバーを停止します。

AWS SDK のインストール

  1. Node.js の AWS SDK関連のドキュメントは、以下にあります。
      「Node.js 内の AWS SDK for JavaScript」
      「Getting Started with the SDK in Node.js」
      「Configuring the SDK in Node.js」
  2. AWS SDK をインストールします。
    c:\projects\mynote>npm install aws-sdk --save
    		
  3. アクセスキーを配置します。
    1. Node.js から、DynamoDB をアクセスするためには、アクセスキーを記述したファイルを配置する必要ずあります。
    2. C:\Users\<ユーザー名>\.aws にcredentials ファイルを置きます
    3. credentials ファイルの内容は以下のようになっています。
      				[default]
      				aws_access_key_id=アクセスキー
      				aws_secret_access_key=シークレットアクセスキー
      				
    4. アクセスキー、シーレットアクセスキーは、AWS IAM コンソールで、ユーザーを作成して、「認証情報」タブの「アクセスキーの作成」で作成します。
      1. ここで、認証情報を表示、または、認証情報のダウンロードをすることで、シークレットアクセスキーを取得できます。
      2. この後、シークレットアクセスキー再取得することはできないので、シークレットアクセスキーを忘れた場合は、新たにユーザーを作成する必要があります。

DynamoDBの構築

  1. AWS DynamoDB にテーブルを作成します。
  2. Node.js でDynamoDBを扱う方法は、AWS の以下にドキュメントがあります。
    Node.js と DynamoDB
  3. DB の形式を以下のように決めます。
    1. テーブル名
      "Notes"
    2. フィールド
      フィールド名 プライマリーキー 内容
      user_id Hash ユーザーID
      date_time Range Noteの生成時間
      この生成時間の順番にnoteを表示します。
      text - Noteのテキストデータ
  4. DynamoDB のテーブルは、AWS コンソール の DynamoDB からも作成できますが、今回は、Node.js のコマンドラインから作成するようにしました。
    以下のコードを NoteCreateTable.js として、作成します。
    <リージョン名> には、DynamoDB を作成するリージョンを指定してください。
    var AWS = require("aws-sdk");
    
    var region = "<リージョン名>";
    
    AWS.config.update({
      region: region,
      endpoint: "https://dynamodb." + region + ".amazonaws.com"
    });
    
    var dynamodb = new AWS.DynamoDB();
    
    var params = {
        TableName : "Notes",
        KeySchema: [       
            { AttributeName: "user_id", KeyType: "HASH"},
            { AttributeName: "date_time", KeyType: "RANGE" }
        ],
        AttributeDefinitions: [       
            { AttributeName: "user_id", AttributeType: "S" },
            { AttributeName: "date_time", AttributeType: "S" }
        ],
        ProvisionedThroughput: {       
            ReadCapacityUnits: 10, 
            WriteCapacityUnits: 10
        }
    };
    
    dynamodb.createTable(params, function(err, data) {
        if (err) {
            console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
        } else {
            console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
        }
    });
    		
  5. Node.js のコマンドプロンプトで、テーブルの生成を行います。
    c:\projects\mynote>node NoteCreateTable.js
    		
  6. AWS DynamoDB コンソールの テーブルを参照すると、"Notes" テーブルが作成されたことを確認できます。

    テーブル概要

サーバーのコード作成

クライアントから、サーバーへのアクセスは、REST API を使用することにします。

サーバーのAPI仕様

REST API は以下の仕様とします。
API method path parameter response
Noteリストの取得 GET /MyNote user_id=ユーザーID
{
    is_success : "true" または、"false",
    operation : "new",
    notes : [
        {
            user_id : ユーザーID,
            date_time : 日時,
            text : テキスト
        },
    ]
}
		
Noteの追加 POST /MyNote/add_note
{
    user_id : ユーザーID,
    date_time : 日時,
    text : テキスト
}
		
{
    is_success : "true" または、"false",
    operation : "add",
    note : {
        user_id : ユーザーID,
        date_time : 日時,
        text : テキスト
    }
}
		
Noteの更新 POST /MyNote/update_note
{
    user_id : ユーザーID,
    date_time : 日時,
    text : テキスト
}
		
{
    is_success : "true" または、"false",
    operation : "update",
    note : {
        user_id : ユーザーID,
        date_time : 日時,
        text : テキスト
    }
}
		
Noteの削除 POST /MyNote/delete_note
{
    user_id : ユーザーID,
    date_time : 日時
}
		
{
    is_success : "true" または、"false"
}
		
全Noteの削除 DELETE /MyNote user_id=ユーザーID
{
    is_success : "true" または、"false"
}
		

サーバーのコード

サーバー側で実装する必要があるのは、以下です。
  • html等の静的ファイルのアクセス指定。
  • REST API の解析
  • AWS SDK を使用した、DynamoDB へのアクセス。
  1. app.js
    1. Node.js のサーバーに置いた、Index.html 等にアクセスできるようにします。
      詳細は、Express の静的ファイルの提供ページを参照してください。
      					app.use(express.static(path.join(__dirname, 'public')));
      				
    2. このアプリケーション用のルーティングモジュールをロードします
      var routeMyNote = require('./routes/routeMyNote');
       …
      app.use('/MyNote', routeMyNote);
      				
  2. routeMyNote.js
    Express のルーティングにREST API の処理を記述します。
    実際の処理はmyNoteServer.js に記述しています。
    1. Noteリストの取得の例
      router.get('/', function(req, res, next) {
      	console.log("/ get note list=" + JSON.stringify(req.query));
      	myNoteServer.getNoteList(req.query.user_id, function(isSuccess, result) {
      		if (isSuccess) {
      			res.json({is_success: "true", operation: "new", notes: result});
      		} else {
      			res.json({is_success: "false", error: result});
      		}
      	});
      });
      				
    2. その他のAPIは、サンプルコードを参照してください。
  3. myNoteServer.js
    DynamoDBにアクセスするコードを実装します。
    1. Noteリストの取得の例
      var AWS = require("aws-sdk");
      
      var region = "<リージョン名>";
      var endpoint = "https://dynamodb." + region + ".amazonaws.com";
      var table = "Notes";
      
      var m_dynamoDB = null;
      var m_dynamodbDoc = null;
      
      function open() {
      	if (m_dynamoDB === null) {
      		console.log('open');
      		m_dynamoDB = new AWS.DynamoDB();
      		m_dynamoDB.config.update({
      		  region: region,
      		  endpoint: endpoint
      		});
      		m_dynamodbDoc = new AWS.DynamoDB.DocumentClient({service:m_dynamoDB});
      	}
      }
      
      exports.getNoteList = getNoteList;
      
      function getNoteList(userId, callback) {
      	open();
      	var params = {
      		TableName: table,
      		KeyConditionExpression: "user_id = :userId",
      		ExpressionAttributeValues: {
      			":userId": userId
      		}
      	};
      	m_dynamodbDoc.query(params, function(err, data) {
      		if (err) {
      			console.log("failed to query.:", JSON.stringify(err, null, 2));
      			callback(false, err);
      		} else {
      			console.log("getNoteList:");
      			var notes = new Array();
      			data.Items.forEach(function(item) {
      				console.log(" -", JSON.stringify(item));
      				var note = {
      					user_id: item.user_id,
      					date_time: item.date_time,
      					text: item.text
      				};
      				notes.push(note);
      			});
      			callback(true, notes);
      		}
      	});
      }
      				
    2. コードの説明
      1. AWS.DynamoDB 作成時、config にリージョン、endpoint を指定します。
        m_dynamoDB = new AWS.DynamoDB();
        m_dynamoDB.config.update({
          region: region,
          endpoint: endpoint
        });
        						
      2. 今回は、DynamoDB のアクセスに、AWS SDK の AWS.DynamoDB.DocumentClient を使用します。
        m_dynamodbDoc = new AWS.DynamoDB.DocumentClient({service:m_dynamoDB});
        						
      3. Noteリストは、AWS.DynamoDB.DocumentClient.query で取得します。
        var params = {
        	TableName: table,
        	KeyConditionExpression: "user_id = :userId",
        	ExpressionAttributeValues: {
        		":userId": userId
        	}
        };
        m_dynamodbDoc.query(params, function(err, data) {
        	if (err) {
        		console.log("failed to query.:", JSON.stringify(err, null, 2));
        		callback(false, err);
        	} else {
        		console.log("getNoteList:");
        		var notes = new Array();
        		data.Items.forEach(function(item) {
        			console.log(" -", JSON.stringify(item));
        			var note = {
        				user_id: item.user_id,
        				date_time: item.date_time,
        				text: item.text
        			};
        			notes.push(note);
        		});
        		callback(true, notes);
        	}
        });
        						
    3. その他のAPIは、サンプルコードを参照してください。

クライアントコードの作成

クライアント側は、UIと、Node.js サーバーの呼び出しコードを作成します。
クライアントのコードには、一部、jQuery を使用しました。
  1. Index.html
    1. 起動時に、user id の入力を行います。
    2. user Id の入力後、サーバーから、noteのリストを取得します。
    3. ダイアログ表示と、noteリストの取得は、以下のコードとなっています。
      $(function(){
      	$("#user_id").dialog({
      		autoOpen: false,
      		modal: true,
      		buttons: {
      			"OK": function() {
      				$(this).dialog('close');
      				g_doc.setUserId(g_userId);
      				g_doc.open();
      				g_doc.loadNote();
      				g_view.updateInfo();
      			},
      			"Cancel": function() {
      				$(this).dialog('close');
      			}
      		}
      	});
      });
      				
      1. g_doc は、myNodeDoc.js に実装があります。
    4. 操作ボタンの説明
      操作ボタン 動作の説明
      send Noteをサーバーに送ります
      Noteのテキストをテキストフィールドにコピーします
      Noteを削除します
      clear all note… 全Noteを削除します
  2. myNoteDoc.js
    1. Note の各処理のコントールはここで行います。
    2. DynamoDB へのアクセスは、m_dbController でつながったモジュールで行います。
    3. この後の、Congnito を使用したDynamoDBのアクセス等は、基本的にこの m_dbControllerを切り替えることで、実現できるようにしています。
      コードは、サンプルコードを参照してください。
  3. myNoteView.js
    Note のリスト表示や、Note の制御(編集, 削除)を行います。
    コードは、サンプルコードを参照してください。
  4. dbControllerServer.js
    Node.js サーバーへのDynamoDBアクセスの要求を行います。
    今回の実装では、jQuery を使用して実装をしました。
    サーバーのAPI仕様で決めた、REST API を$.ajax を使用して呼び出しています。
    this.getNoteList = function(userId, callback) {
    	$.ajax({
    		'url':'/MyNote',
    		'type':'GET',
    		'dataType': 'json',
    		'data': {
    			'user_id' : userId
    		}
    	}).done(function(data){
    		if (data.is_success === 'true') {
    			callback(true, data.operation, data.notes);
    		} else {
    			callback(false, data.error, null);
    		}
    	}).fail(function(data){
    		callback(false, data, null);
    	});
    };
    		

ローカル環境での動作確認

ここまでで、実装は、すべて終了したので、ローカルPC上で動作確認をします。
  1. サーバーの起動
    Node.js のコマンドプロンプトで、サーバーを起動します。
    c:\projects\mynote>set DEBUG=mynote:* & npm start
    
    > mynote@0.0.0 start c:\projects\mynote
    > node ./bin/www
    
      mynote:server Listening on port 3000 +0ms
    		
  2. Web Browser から、http://localhost:3000 にアクセスして、Note の登録、削除等アプリケーションが動作することを確認します。
  3. うまく行かない場合は、console.log 等を使ってデバッグしてください。

EC2へのアップロード

ローカル環境で動作確認ができたならば、サーバーにアップロードして、サーバー環境で動作確認をします。
  1. Node.jsのインストール
    Node.jsより、Node.js を取得して、EC2にインストールします。
    インストール方法の詳細は、Node.js のホームページを参照してください。
  2. EC2 の環境作成 (forever のインストール)
    EC2 のターミナル上で、Node.js でサーバーを起動した後、ターミナルを終了すると、サーバーが終了してしまうため、forever を使用して、サーバーをデーモンにします。
    sudo npm install forever -g
    		
  3. アップロード
    ローカルの実行環境をそのまま WinSCP 等を使用して、EC2 にアップロードします。
    ここでは、~/mynote ディレクトリに配置するようにしました。
  4. サーバーの起動
    cd ~/mynote
    forever start bin/www
    		
  5. Web Browser で、EC2 のパブリックDNSのポート3000 にアクセスすると、EC2上で動作する、MyNoteアプリケーションを使用できます。
    Note の登録、削除等を行ってみてください。
    パブリックDNS は、AWS コンソールの EC2 のインスタンス情報で確認することができます。
    また、Elastic IP アドレスを取得すると、EC2 を起動しなおした後でも、同じアドレスが使えるので便利です。
    Elsatic IP アドレスについては、AWS の以下にドキュメントがあります。
    1. Elastic IP アドレス

サンプルコードの実行方法

  • mynote-sample-nodejs.zip をダウンロードしてください。
  • ダウンロード後、zip ファイルを展開してください。
  • zipファイルの中には、Node.js のmodule は含まれていないので、npm install で、各 module のインストールが必要です。
    c:\projects>cd mynote
    c:\projects\mynote>npm install
    		
  • mynote\myNoteServer.js のリージョン名を指定してください。
    var region = "<リージョン名>";
    		
  • mynote\NoteCreateTable.js のリージョン名を指定してください。
    var region = "<リージョン名>";
    		

次回

次は、Cognitoを使用したアプリケーション作成でAWS Cognitoのユーザー認証を使用したDynamoDBののアクセスの制御を追加します。