在开发无服务器应用的时候,通过纯手工方式创建各种资源的话,效率会非常低,因此需要借助一些框架来提高开发效率。下面介绍如何在serverless中开发DynamoDB API(Lambda)。

serverless教程
使用serverless添加Query方法
访问DynamoDB的公共方法
首先增加文件api/common/dynamo/Dynamo.js
Javascript
const AWS = require('aws-sdk');
const documentClient = new AWS.DynamoDB.DocumentClient();
const Dynamo = {
async query(params) {
const data = await documentClient
.query(params)
.promise()
if (!data || !data.Items) {
throw Error(`Error occured while fetching the data`);
}
return data.Items;
}
}
module.exports = Dynamo;
增加具体的Lambda方法
增加文件api/scores/getScores.js:
Javascript
const Responses = require('../common/Responses');
const Dynamo = require('../common/dynamo/Dynamo');
exports.handler = async event => {
// 从serverless.yml定义中获取tableName
const tableName = process.env.tableName;
if (!event.pathParameters || !event.pathParameters.studentID) {
return Responses.HTTP_400({message: 'missing the studentID from the URL.'});
}
let studentID = event.pathParameters.studentID;
const params = {
KeyConditionExpression: 'StudentID = :studentId',
ExpressionAttributeValues: { ':studentId': studentID},
TableName: tableName
};
const scores = await Dynamo.query(params).catch(err => {
console.log("error while getting scores from DynamoDB", err);
return null;
})
if(!scores) {
return Responses.HTTP_400({message: "Failed to find scores by studentID."});
}
return Responses.HTTP_200({message: scores})
}
如果同时使用PK和SK进行查询的话,可以更改params:
Javascript
const params = {
KeyConditionExpression: 'StudentID = :studentId AND Subject = :subject',
ExpressionAttributeValues: { ':studentId': studentID, ':subject': 'Math' },
TableName: tableName
};
serverless.yml中的定义
需要注意,在定义DynamoDB访问权限的时候,不仅要定义对表各种操作的权限,还需要定义对index的权限,否则会报错。
yaml
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.tableName}/index/*"
完整代码:
yaml
service: service-05-api-dynamodb
provider:
name: aws
region: eu-west-1
runtime: nodejs14.x
lambdaHashingVersion: 20201221
profile: default
environment:
tableName: ${self:custom.tableName}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.tableName}"
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.tableName}/index/*"
custom:
tableName: student-scores
resources:
Resources:
MyDynamoDbTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.tableName}
AttributeDefinitions:
- AttributeName: StudentID
AttributeType: S
- AttributeName: Subject
AttributeType: S
- AttributeName: Date
AttributeType: S
KeySchema:
- AttributeName: StudentID
KeyType: HASH
- AttributeName: Subject
KeyType: RANGE
GlobalSecondaryIndexes:
- IndexName: Dates
KeySchema:
- AttributeName: Date
KeyType: HASH
- AttributeName: Subject
KeyType: RANGE
Projection:
ProjectionType: ALL
BillingMode: PAY_PER_REQUEST
functions:
getScores:
handler: api/scores/getScores.handler
events:
- http:
path: get-scores/{studentID}
method: GET
cors: true
plugins:
- serverless-webpack
package:
individually: true
测试
发布
bash
sls deploy
测试get-scores
然后直接访问这样的网址就可以获取数据了:
https://xxxxxx.execute-api.eu-west-1.amazonaws.com/dev/get-scores/9901
使用serverless对DynamoDB写入数据
更新api/common/dynamo/Dynamo.js
首先增加对DynamoDB进行写入的方法:
Javascript
async insert (params) {
const res = await documentClient.put(params).promise();
if(!res) {
throw Error(`There was an error while inserting the data`);
}
return params.Item;
}
增加api/scores/insertScore.js
接下来创建文件:api/scores/insertScore.js:
Javascript
const Responses = require('../common/Responses');
const Dynamo = require('../common/dynamo/Dynamo');
const tableName = process.env.tableName;
exports.handler = async event => {
const score = JSON.parse(event.body);
let params = {
TableName: tableName,
Item: {
"StudentID": score.studentId,
"Subject": score.subject,
"Score": score.score,
"Date": score.date
}
};
const newScore = await Dynamo.insert(params).catch(err => {
console.log('error in dynamo insert', err);
return null;
});
console.log(newScore);
if (!newScore) {
return Responses.HTTP_400({ message: 'Failed to insert data' });
}
return Responses.HTTP_200({ newScore });
};
这里要特别注意,代码中的字段名字一定要和DynamoDB中的一致,包括大小写,否则会出错。
更新serverless.yml
yaml
functions:
insertScore:
handler: api/scores/insertScore.handler
events:
- http:
path: new-score
method: POST
cors: true
测试
重新部署:
bash
sls deploy
接下来可以使用类似Postman的工具测试。也可以使用这个在线工具进行测试:https://reqbin.com/

serverless教程