无服务器 – 带有 DynamoDB 的 REST API

无服务器 – 带有 DynamoDB 的 REST API


到目前为止,我们已经学习了几个与无服务器 lambda 部署相关的概念。现在是看一些例子的时候了。在本章中,我们将查看 Serverless 官方提供的示例之一。顾名思义,我们将创建一个 REST API。正如您所猜到的,我们所有的 lambda 函数都将由 API 网关触发。我们的 lambda 函数将与 dynamoDB 表进行交互,该表本质上是一个待办事项列表,用户将能够使用端点执行多项操作,例如创建新项目、获取现有项目、删除项目等。在部署后公开。如果您不熟悉 REST API,那么您可以在此处阅读有关它们的更多信息

代码演练

代码可以在 GitHub 上找到 – https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-dynamodb

我们将看一下项目结构,讨论一些我们目前还没有看到的新概念,然后执行 serverless.yml 文件的演练。所有函数处理程序的演练将是多余的。因此,我们将只介绍一个函数处理程序。您可以将理解其他功能作为练习。

项目结构

现在,如果您查看项目结构,则 lambda 函数处理程序都位于 todos 文件夹中的单独 .py 文件中。serverless.yml 文件在每个函数处理程序的路径中指定了 todos 文件夹。没有外部依赖项,因此没有 requirements.txt 文件。

新概念

现在,您可能第一次看到几个术语。让我们快速扫描这些 –

  • dynamoDB – 这是 AWS 提供的 NoSQL(不仅是 SQL)数据库。虽然不完全准确,但从广义上讲,NoSQL 之于 SQL,就像 Word 之于 Excel。您可以在此处阅读有关 NoSQL 的更多信息NoSQL 数据库有 4 种类型 – 文档数据库、键值数据库、宽列存储和图形数据库。dynamoDB 是一个键值数据库,这意味着您可以不断地将键值对插入到数据库中。这类似于redis缓存。您可以通过引用其键来检索该值。

  • boto3 – 这是适用于 Python 的 AWS 开发工具包。如果您需要在 lambda 函数中配置、管理、调用或创建 AWS 的任何服务(EC2、dynamoDB、S3 等),则需要 boto3 SDK。您可以在此处阅读有关 boto3 的更多信息

除此之外,我们在演练 serverless.yml 和处理程序函数的过程中还会遇到一些概念。我们将在那里讨论它们。

serverless.yml 演练

serverless.yml 文件以服务的定义开始。

service: serverless-rest-api-with-dynamodb

然后通过以下行声明框架版本范围 –

frameworkVersion: ">=1.1.0 <=2.1.1"

这就像支票一样。如果您的无服务器版本不在此范围内,则会引发错误。当您共享代码并希望使用此 serverless.yml 文件的每个人都使用相同的 serverless 版本范围以避免出现问题时,这会有所帮助。

接下来,在提供程序中,我们看到了两个迄今为止尚未遇到的额外字段 – environmentiamRoleStatements

provider:
   name: aws
   runtime: python3.8
   environment:
      DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}
   iamRoleStatements:
      - Effect: Allow
         Action:
         - dynamodb:Query
         - dynamodb:Scan
         - dynamodb:GetItem
         - dynamodb:PutItem
         - dynamodb:UpdateItem
         - dynamodb:DeleteItem
         Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:
         *:table/${self:provider.environment.DYNAMODB_TABLE}"

Environment,如您所料,用于定义环境变量。此 serverless.yml 文件中定义的所有函数都可以获取这些环境变量。我们将在下面的函数处理程序演练中看到一个示例。在这里,我们将 dynamoDB 表名称定义为环境变量。

$符号表示的变量。自我关键字指serverless.yml文件本身,而选择是指一个选项,我们可以在提供SLS部署因此,表名将是服务名称,后跟一个连字符,然后是文件找到的第一个阶段参数:无服务器部署期间的选项可用,或提供者阶段,默认情况下dev。因此,在这种情况下,如果您在无服务器部署期间不提供任何选项,则 dynamoDB 表名称将为 serverless-rest-api-with-dynamodb-dev。您可以在此处阅读有关无服务器变量的更多信息

iamRoleStatements定义提供给函数的权限。在这种情况下,我们允许函数对 dynamoDB 表执行以下操作 – QueryScanGetItemPutItemUpdateItemDeleteItem资源名称指定允许这些操作的确切表。如果您输入了“*”代替资源名称,您将允许对所有表进行这些操作。但是,在这里,我们希望只允许对一个表进行这些操作,因此,使用标准 arn 格式在资源名称中提供了该表的 arn(Amazon 资源名称)。这里再次使用选项区域(在无服务器部署期间指定)或提供程序中提到的区域(默认为 us-east-1)中的第一个区域。

在函数部分,函数是按照标准格式定义的。请注意,get、update、delete 都具有相同的路径,其中 id 作为路径参数。但是,每个方法都不同。

functions:
   create:
      handler: todos/create.create
      events:
         - http:
            path: todos
            method: post
            cors: true
   list:
      handler: todos/list.list
      events:
         - http:
            path: todos
            method: get
            cors: true
   get:
      handler: todos/get.get
      events:
         - http:
            path: todos/{id}
            method: get
            cors: true

   update:
      handler: todos/update.update
      events:
         - http:
            path: todos/{id}
            method: put
            cors: true
   delete:
      handler: todos/delete.delete
      events:
         - http:
            path: todos/{id}
            method: delete
            cors: true

后来,我们遇到了另一个我们以前没有见过的资源块。此块基本上可以帮助您在 CloudFormation 模板中指定需要创建的资源,以使函数正常工作。在这种情况下,我们需要为函数创建一个 dynamoDB 表。到目前为止,我们已经指定了表的名称,甚至引用了它的 ARN。但是我们还没有创建表。资源块中指定表的特征将为我们创建该表。

resources:
   Resources:
      TodosDynamoDbTable:
         Type: 'AWS::DynamoDB::Table'
         DeletionPolicy: Retain
         Properties:
         AttributeDefinitions:
            -
               AttributeName: id
               AttributeType: S
         KeySchema:
            -
               AttributeName: id
               KeyType: HASH
         ProvisionedThroughput:
            ReadCapacityUnits: 1
            WriteCapacityUnits: 1
            TableName: ${self:provider.environment.DYNAMODB_TABLE}

这里定义了很多配置,其中大部分特定于 dynamoDB。简而言之,我们要求无服务器创建一个“TodosDynamoDbTable”,或输入“DynamoDB Table”,其中 TableName(在底部提到)等于在 provider 的环境变量中定义的那个。我们将其删除策略设置为“保留”,这意味着如果删除堆栈,则保留资源。这里我们说该表将有一个名为id的属性,其类型将为 String。我们还指定 id 属性将是 HASH 键或分区键。您可以在此处阅读有关 dynamoDB 表中 KeySchemas 的更多信息最后,我们指定表的读取容量和写入容量。

就是这样!我们的 serverless.yml 文件现已准备就绪。现在,由于所有函数处理程序或多或少相似,我们将只介绍一个处理程序,即 create 函数的处理程序。

创建函数处理程序的演练

我们有几个导入语句

import json
import logging
import os
import time
import uuid

接下来,我们导入 boto3,如上所述,它是适用于 Python 的 AWS 开发工具包。我们需要 boto3 从 lambda 函数内与 dynamoDB 接口。

import boto3
dynamodb = boto3.resource('dynamodb')

接下来,在实际的函数处理程序中,我们首先检查“事件”有效负载的内容(create API 使用 post 方法)。如果它的正文不包含“文本”键,我们还没有收到要添加到待办事项列表的有效项目。因此,我们提出了一个例外。

def create(event, context):
   data = json.loads(event['body'])
   if 'text' not in data:
      logging.error("Validation Failed")
      raise Exception("Couldn't create the todo item.")

考虑到我们按预期获得了 ‘text’ 键,我们准备将其添加到 dynamoDB 表中。我们获取当前时间戳,并连接到 dynamoDB 表。注意 serverless.yml 中定义的环境变量是如何获取的(使用 os.environ)

timestamp = str(time.time())
table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])

接下来,我们通过使用 uuid 包生成随机 uuid,使用接收到的数据作为文本,将 createdAt 和 updatedAt 设置为当前时间戳,并将字段 ‘checked’ 设置为 False 来创建要添加到表中的项目。‘checked’ 是另一个可以使用更新操作更新的字段,除了文本之外。

item = {
   'id': str(uuid.uuid1()),
   'text': data['text'],
   'checked': False,
   'createdAt': timestamp,
   'updatedAt': timestamp,
}

最后,我们将项目添加到 dynamoDB 表并将创建的项目返回给用户。

# write the todo to the database
table.put_item(Item=item)

# create a response
response = {
   "statusCode": 200,
   "body": json.dumps(item)
}
return response

通过本演练,我认为其他函数处理程序将不言自明。在某些函数中,您可能会看到此语句 – “body” – json.dumps(result[‘Item’], cls=decimalencoder.DecimalEncoder)。这是用于json.dumps 中错误的解决方法json.dumps 默认不能处理十进制数,因此,decimalencoder.py文件已经被创建来包含处理这个的 DecimalEncoder 类。

恭喜您了解您使用无服务器创建的第一个综合项目。该项目的创建者还在README文件中分享了他的部署端点以及测试这些功能的方法看一看。前往下一章查看另一个示例。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁