如何使用SAM CLI部署API网关、Lambda(Node.js)和DynamoDB?
我正在尝试在本地系统中创建应用程序,并使用SAM CLI将其部署到AWS云。图中给出了该应用程序的基本轮廓 我已经为此应用程序创建了一个名为myproj的目录,所有子文件夹和文件如下图所示 template.yaml文件由以下代码组成-如何使用SAM CLI部署API网关、Lambda(Node.js)和DynamoDB?,node.js,aws-lambda,amazon-dynamodb,aws-api-gateway,serverless-application-model,Node.js,Aws Lambda,Amazon Dynamodb,Aws Api Gateway,Serverless Application Model,我正在尝试在本地系统中创建应用程序,并使用SAM CLI将其部署到AWS云。图中给出了该应用程序的基本轮廓 我已经为此应用程序创建了一个名为myproj的目录,所有子文件夹和文件如下图所示 template.yaml文件由以下代码组成- AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: myDB: Type: AWS::Serverless::Simpl
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
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);
};
在functionRead文件夹中,package.json包含以下内容-
{
"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"
}
}
而read.js文件包含以下代码-
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
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);
};
在functionWrite文件夹中,文件package.json包含以下内容-
{
"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"
}
}
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);
};
文件write.js包含以下内容-
{
"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"
}
}
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);
};
然后,我导航回终端中的myproj目录,并运行命令sambuild
。
构建完成后,我运行命令samdeploy--guided
,并按照步骤将堆栈部署到云中。然后,我检查了控制台,确认部署成功。
然后,在终端中,我运行了curl-xpost-d'{“id”:“one”,“name”:“john”}'https://0000000000.execute-api.ap-south-1.amazonaws.com/Prod/writedb
。但是我得到了{消息:“内部服务器错误”}
为了确认lambda和dynamoDB是否正确链接,我转到lambda控制台,为lambda函数创建了一个测试事件,该函数名为write.js,具有相同的负载{id:“one”,“name:“john”}
。它成功运行并将这两项输入到dyanmoDB表中。类似地,我为lambda函数创建了另一个测试事件,其名称为read.js,负载为{“id”:“one”}
。它还成功运行并显示了数据
为了确认API网关和lambda是否正确链接,我在API网关中对资源/writedb
和/readdb
运行了测试,但它给了我{message:'Internal server Error'}
请帮助我解决此问题。来自API网关调用的事件对象将具有以下结构-
{
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
}
从上面的JSON对象事件中,我们需要主体。因为主体是一个字符串,所以我们需要将其转换为JSON对象
因此,write.js应该修改为-
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;
};
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;
};
类似地,read.js将被修改为-
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;
};
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;
};
因此,这将解决问题。和template.yaml文件也是正确的。我看不到您在模板中声明API网关的部分。yaml AWS::Serverless::API您能包括这一部分吗?否则,如何获得端点和阶段?根据AWS文档,AWS::Serverless::Api资源不需要显式添加到AWS Serverless应用程序定义模板中。此类型的资源是从模板中定义的AWS::Serverless::Function资源上定义的Api事件的联合隐式创建的,这些资源未引用AWS::Serverless::Api资源。见-。尽管我找到了解决这个问题的办法,我还是要写在答案里。谢谢你的关心。