简体   繁体   中英

How to deploy API gateway, Lambda(Node.js) and DynamoDB using SAM CLI?

I am trying to create an application in my local system and deploy it to the AWS cloud using SAM CLI. The basic outline of this application is given in the diagram.

在此处输入图片说明

I have created a directory named myproj for this application and all the sub-folders and files are shown in the following diagram.

在此处输入图片说明

The template.yaml file consists of the following code -

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  myDB:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: tabmine
      PrimaryKey:
        Name: id
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5
        
  LambdaWrite:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: functionWrite/
      Handler: write.handler
      Runtime: nodejs12.x
      Events:
        apiForLambda:
          Type: Api 
          Properties:
            Path: /writedb
            Method: post
      Policies:
        DynamoDBWritePolicy:
          TableName: !Ref myDB
            
  LambdaRead:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: functionRead/
      Handler: read.handler
      Runtime: nodejs12.x
      Events:
        apiForLambda:
          Type: Api 
          Properties:
            Path: /readdb
            Method: post
      Policies:
        DynamoDBReadPolicy:
          TableName: !Ref myDB

In the functionRead folder, package.json has the following contents -

{
  "name": "myproj",
  "version": "1.0.0",
  "description": "",
  "main": "read.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "aws-sdk": "^2.783.0"
  }
}

And the read.js file contains the following code -

var AWS = require('aws-sdk');

var ddb = new AWS.DynamoDB.DocumentClient();

exports.handler = function(event, context, callback) {
    var ID = event.id;
    
    var params = {
        TableName: 'tabmine',
        Key: {
            'id': ID
        }
    };
    
    ddb.get(params, callback);
    
};

In functionWrite folder, the file package.json has the following content -

{
  "name": "myproj",
  "version": "1.0.0",
  "description": "",
  "main": "write.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "aws-sdk": "^2.783.0"
  }
}

And the file write.js has the following content -

var AWS = require('aws-sdk');

var ddb = new AWS.DynamoDB.DocumentClient();

exports.handler = function(event, context, callback) {
    

    var ID = event.id;
    var NAME = event.name;
    
    var params = {
        TableName: 'tabmine',
        Item: {
            'id': ID,
            'name': NAME
        }
    };
    
    ddb.put(params, callback);
    
};

Then, I have navigated back to the myproj directory in the terminal and ran the command sam build . After building was done, I ran the command sam deploy --guided and followed the steps to deploy the stack to the cloud. Then, I checked the console to confirm the deployment and it was successful. Then, in the terminal, I ran curl -X POST -d '{"id":"one","name":"john"}' https://0000000000.execute-api.ap-south-1.amazonaws.com/Prod/writedb . But I got {message : 'Internal server Error'} .

To confirm if the lambda and dynamoDB are correctly linked or not, I went to Lambda console and created a test event for the lambda function with name write.js with the same payload {"id":"one","name":"john"} .It ran successfully and entered the those two items into the dyanmoDB table. Similarly, I have created another test event for the lambda function with name read.js and with payload {"id":"one"} . It also ran successfully and displayed the datas.

To confirm if the API gateway and the lambdas are are correctly linked or not, I ran the test in API gateway for both the resources /writedb and /readdb , but it is giving me {message : 'Internal server Error'} .

Please help me out of this problem.

The event object that will come from the API gateway invocation will have the following structure -

{
  resource: '/func1',
  path: '/func1',
  httpMethod: 'POST',
  headers: {
    accept: '*/*',
    'content-type': 'application/x-www-form-urlencoded',
    Host: '0000000000.execute-api.ap-south-1.amazonaws.com',
    'User-Agent': 'curl/7.71.1',
    'X-Amzn-Trace-Id': 'Root=1-5fa018aa-60kdfkjsddd5f6c6c07a2',
    'X-Forwarded-For': '178.287.187.178',
    'X-Forwarded-Port': '443',
    'X-Forwarded-Proto': 'https'
  },
  multiValueHeaders: {
    accept: [ '*/*' ],
    'content-type': [ 'application/x-www-form-urlencoded' ],
    Host: [ '0000000000.execute-api.ap-south-1.amazonaws.com' ],
    'User-Agent': [ 'curl/7.71.1' ],
    'X-Amzn-Trace-Id': [ 'Root=1-5fa018aa-603d90fhgdhdgdjhj6c6dfda2' ],
    'X-Forwarded-For': [ '178.287.187.178' ],
    'X-Forwarded-Port': [ '443' ],
    'X-Forwarded-Proto': [ 'https' ]
  },
  queryStringParameters: null,
  multiValueQueryStringParameters: null,
  pathParameters: null,
  stageVariables: null,
  requestContext: {
    resourceId: 'scsu6k',
    resourcePath: '/func1',
    httpMethod: 'POST',
    extendedRequestId: 'VYjfdkjkjfjkfuA=',
    requestTime: '02/Nov/2020:14:33:14 +0000',
    path: '/test/func1',
    accountId: '00000000000',
    protocol: 'HTTP/1.1',
    stage: 'test',
    domainPrefix: 'f8h785q05a',
    requestTimeEpoch: 1604327594697,
    requestId: '459e0256-9c6f-4a24-bcf2-05520d6bc58a',
    identity: {
      cognitoIdentityPoolId: null,
      accountId: null,
      cognitoIdentityId: null,
      caller: null,
      sourceIp: '178.287.187.178',
      principalOrgId: null,
      accessKey: null,
      cognitoAuthenticationType: null,
      cognitoAuthenticationProvider: null,
      userArn: null,
      userAgent: 'curl/7.71.1',
      user: null
    },
    domainName: '000000000.execute-api.ap-south-1.amazonaws.com',
    apiId: 'lkjfslkfj'
  },
  body: '{"id":"1","name":"John"}',
  isBase64Encoded: false
}

From the above event which is JSON object, we need the body . Since, the body is a string, so we need to convert it into JSON object.

So, write.js should be modified to -

var AWS = require('aws-sdk');
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

exports.handler = async (event) => {
    try {
        
            //console.log(event);
            //console.log(event.body);
            var obj = JSON.parse(event.body);
        
            //console.log(obj.id);
            //console.log(obj.name);
        
            var ID = obj.id;
            var NAME = obj.name;
        
        
            var params = {
                TableName:'tabmine',
                Item: {
                 id : {S: ID}, 
                 name : {S: NAME}
                }
            
            };
        
            var data;
            var msg;
            
            try{
                data = await ddb.putItem(params).promise();
                console.log("Item entered successfully:", data);
                msg = 'Item entered successfully';
            } catch(err){
                console.log("Error: ", err);
                msg = err;
            }
        
        
            var response = {
                'statusCode': 200,
                'body': JSON.stringify({
                    message: msg
            })
        };
    } catch (err) {
        console.log(err);
        return err;
    }

    return response;
};

Similarly, read.js will get modified to -

var AWS = require('aws-sdk');
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

exports.handler = async (event) => {
    try {
        
            //console.log(event);
            //console.log(event.body);
            var obj = JSON.parse(event.body);
        
            //console.log(obj.id);
            //console.log(obj.name);
        
            var ID = obj.id;
        
        
            var params = {
                TableName:'tabmine',
                Key: {
                 id : {S: ID}
                }
            
            };
        
            var data;
            
            try{
                data = await ddb.getItem(params).promise();
                console.log("Item read successfully:", data);
            } catch(err){
                console.log("Error: ", err);
                data = err;
            }
        
        
            var response = {
                'statusCode': 200,
                'body': JSON.stringify({
                    message: data
            })
        };
    } catch (err) {
        console.log(err);
        return err;
    }

    return response;
};

So, this will solve the problem. And template.yaml file is also correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM