如何使用 SAM CLI 部署 API 网关、Lambda(Node.js) 和 DynamoDB?
How to deploy API gateway, Lambda(Node.js) and DynamoDB using SAM CLI?
我正在尝试在我的本地系统中创建一个应用程序并使用 SAM CLI 将其部署到 AWS 云。图中给出了该应用程序的基本轮廓。
我为此应用程序创建了一个名为 myproj 的目录,所有子文件夹和文件如下图所示。
template.yaml文件由以下代码组成-
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
在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文件包含以下代码-
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"
}
}
并且文件write.js有以下内容-
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 目录并 运行 命令 sam build
。
构建完成后,我 运行 命令 sam deploy --guided
并按照步骤将堆栈部署到云端。然后,我查看控制台确认部署成功。
然后,在终端中,我 运行 curl -X POST -d '{"id":"one","name":"john"}' https://0000000000.execute-api.ap-south-1.amazonaws.com/Prod/writedb
。但是我得到了 {message : 'Internal server Error'}
.
为了确认 lambda 和 dynamoDB 是否正确链接,我转到 Lambda 控制台并为名称为 [的 lambda 函数创建了一个测试事件write.js 具有相同的负载 {"id":"one","name":"john"}
。它 运行 成功并将这两项输入到 dyanmoDB table。同样,我为名称为 read.js 且负载为 {"id":"one"}
的 lambda 函数创建了另一个 测试事件 。它还 运行 成功并显示了数据。
为了确认 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 对象事件,我们需要 body。因为,正文是一个字符串,所以我们需要将它转换成 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;
};
同样,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 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文件也是正确的。
我正在尝试在我的本地系统中创建一个应用程序并使用 SAM CLI 将其部署到 AWS 云。图中给出了该应用程序的基本轮廓。
我为此应用程序创建了一个名为 myproj 的目录,所有子文件夹和文件如下图所示。
template.yaml文件由以下代码组成-
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
在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文件包含以下代码-
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"
}
}
并且文件write.js有以下内容-
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 目录并 运行 命令 sam build
。
构建完成后,我 运行 命令 sam deploy --guided
并按照步骤将堆栈部署到云端。然后,我查看控制台确认部署成功。
然后,在终端中,我 运行 curl -X POST -d '{"id":"one","name":"john"}' https://0000000000.execute-api.ap-south-1.amazonaws.com/Prod/writedb
。但是我得到了 {message : 'Internal server Error'}
.
为了确认 lambda 和 dynamoDB 是否正确链接,我转到 Lambda 控制台并为名称为 [的 lambda 函数创建了一个测试事件write.js 具有相同的负载 {"id":"one","name":"john"}
。它 运行 成功并将这两项输入到 dyanmoDB table。同样,我为名称为 read.js 且负载为 {"id":"one"}
的 lambda 函数创建了另一个 测试事件 。它还 运行 成功并显示了数据。
为了确认 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 对象事件,我们需要 body。因为,正文是一个字符串,所以我们需要将它转换成 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;
};
同样,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 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文件也是正确的。