aws dynamodb_使用AWS Lambda和DynamoDB构建Swift无服务器REST API

墨寂弦
2023-12-01

aws dynamodb

Last month, The Swift Core Team & Swift Server Work Group had announced the availability of Swift AWS Lambda Runtime as well as support of Swift on Amazon Linux 2 OS. With both of this announcement, we finally have some official support to run Swift on AWS Lambda environment.

上个月,Swift核心团队和Swift Server工作组宣布了Swift AWS Lambda Runtime的可用性以及对Amazon Linux 2 OS上Swift的支持。 有了这两个公告,我们终于获得了一些官方支持,可以在AWS Lambda环境上运行Swift。

Swift has many advantages such as low memory footprint, high performance, and quick start time. The Swift AWS Lambda runtime also uses SwiftNIO to provide high performance non blocking networking engine for us to run asynchronous event driven code.

Swift具有许多优势,例如低内存占用,高性能和快速启动时间。 Swift AWS Lambda运行时还使用SwiftNIO为我们提供了高性能的非阻塞网络引擎,以运行异步事件驱动的代码。

The runtime itself provides built-in support for many Lambda supported events such as HTTP request event from API Gateway, S3 object storage event, Simple Notification Service, and Simple Queue Service.

运行时本身为许多Lambda支持的事件提供了内置支持,例如来自API网关的HTTP请求事件,S3对象存储事件,简单通知服务和简单​​队列服务。

我们将建立什么 (What We Will Build)

In this tutorial, we’ll build a simple Swift Serverless REST API endpoints to create, update, delete, and retrieve list of todo. Here are the topics we’ll learn:

在本教程中,我们将构建一个简单的Swift Serverless REST API端点,以创建,更新,删除和检索待办事项列表。 以下是我们将学习的主题:

  1. Swift Lambda Runtime to handle API Gateway request event.

    Swift Lambda Runtime来处理API网关请求事件。
  2. Swift AWS DynamoDB SDK to persist the todo data in the Cloud.

    Swift AWS DynamoDB SDK将待办事项数据持久存储在云中。
  3. SwiftNIO to handle asynchronous event processing in network using EventLoopFuture.

    SwiftNIO使用EventLoopF​​uture处理网络中的异步事件处理。
  4. Docker to build and package the Swift binary ready for AWS Lambda Custom provided runtime.

    Docker构建和打包Swift二进制文件,可用于AWS Lambda Custom提供的运行时。
  5. Serverless Framework to provision and deploy to AWS Lambda with IAM Role.

    无服务器框架,以IAM角色调配和部署到AWS Lambda。

You can download the completed project Source from the GitHub repository. I have provided the backend and iOS client app under one repository. Please follow the instruction on the README file to build.

您可以从GitHub存储库下载完整的项目源。 我在一个存储库下提供了backendiOS client应用程序。 请按照README文件上的说明进行构建。

You can also watch the full video tutorial from YouTube.

您也可以观看YouTube上的完整视频教程。

Let’s begin to create a new Swift project and build the Todos REST API app!

让我们开始创建一个新的Swift项目并构建Todos REST API应用程序!

项目和依赖项设置 (Project & Dependencies Setup)

First, let’s open terminal, create a new directory named TodoAPI. You can put it anywhere you want.

首先,让我们打开终端,创建一个名为TodoAPI的新目录。 您可以将其放置在任何位置。

mkdir TodoAPI && cd TodoAPI

Create a new swift executable using swift package init passing executable to the type flag. If you are using macOS, double click on the Package.swift file to open the project in Xcode automatically.

使用swift包init将可执行文件传递给type标志来创建一个新的swift可执行文件。 如果您使用的是macOS,请双击Package.swift文件以自动在Xcode中打开项目。

swift package init --type executable

Let’s add the required dependencies for our backend app. Open Package.swift file from the navigator and copy the following code.

让我们为后端应用程序添加必需的依赖项。 从导航器中打开Package.swift文件,然后复制以下代码。

Here’s the things the we have added in the package:

这是我们在软件包中添加的内容:

  • macOS v10_14 as the platform.

    macOS v10_14为平台。

  • Swift AWS Lambda Runtime package provided by The Swift Server Work Group, currently the version is 0.2.0 and its in pre-release stage.

    由The Swift Server Work Group提供的Swift AWS Lambda Runtime软件包,当前版本是0.2.0并且处于预发行阶段。

  • Swift AWS SDK, this package provides native Swift API for us to interact with various AWS Services such as DynamoDB, S3, and many more.

    Swift AWS SDK,此软件包为我们提供了本机Swift API,可与各种AWS服务(例如DynamoDB,S3等)进行交互。
  • AWSDynamoDB, AWSLambdaRuntime, and AWSLambdaEvents added as the dependencies into the TodoAPI target.

    将AWSDynamoDB,AWSLambdaRuntime和AWSLambdaEvents作为依赖项添加到TodoAPI目标中。

Make sure to save the file using Command + S shortcut. This will download and the resolve all the dependencies. You can view the progress from the dependencies section on the navigator.

确保使用Command + S快捷方式保存文件。 这将下载并解析所有依赖项。 您可以从导航器上的“依赖项”部分查看进度。

After all packages has been downloaded, try to build and run to make sure there is no build time error.

下载所有软件包后,尝试构建并运行以确保没有构建时间错误。

处理函数调用 (Handling Function Invocation)

Let’s explore on how AWS Lambda Runtime handle the function invoked. There are 2 types of handler provided by the Swift AWS Lambda Runtime.

让我们探讨一下AWS Lambda Runtime如何处理调用的函数。 Swift AWS Lambda运行时提供了两种处理程序。

The first one is to use closure/callback. In this example, the request payload is a string, it can be also a JSON that conforms to decodable, and various AWS events such as S3, API Gateway, and many more. Make sure to invoke callback passing the response we want to return in the function.

第一个是使用闭包/回调。 在此示例中,请求有效负载是一个字符串,它也可以是符合可解码的JSON,以及各种AWS事件,例如S3,API Gateway等。 确保调用回调以传递要在函数中返回的响应。

import AWSLambdaRuntimeLambda.run { (context, payload: String, callback) in
callback(.success("Hello, \(payload)"))
}

The second one is to use EventLoopLambdaHandler, which is more suited to performance sensitive function, in this case the function will run in the same thread as the networking handlers, so no need for performance cost because of context switching between networking and processing threads. It used SwiftNIO EventLoop primitives, in this case our handler will return an event loop.

第二种方法是使用EventLoopLambdaHandler ,它更适合对性能敏感的功能,在这种情况下,该功能将在与网络处理程序相同的线程中运行,因此由于在网络线程和处理线程之间进行上下文切换,因此不需要性能成本。 它使用了SwiftNIO EventLoop原语,在这种情况下,我们的处理程序将返回一个事件循环。

If you are familiar with Javascript, the EventLoop concept is very similar to a Promise, which means the value will be resolved in the future. We’ll be using the EventLoopLambdaHandler to build our REST API.

如果您熟悉Javascript,则EventLoop概念与Promise非常相似,这意味着该值将在future得到解决。 我们将使用EventLoopLambdaHandler来构建REST API。

建立Todo模型 (Building Todo Model)

Let’s create the model for the Todo first, create new directory named Models, and create a new Swift file named Todo. Then, let’s create a Todo struct that conforms to Codable protocol. It has six properties:

让我们首先为Todo创建模型,创建名为Models的新目录,并创建名为Todo的新Swift文件。 然后,让我们创建一个符合Codable协议的Todo结构。 它具有六个属性:

  1. id as String.

    idString

  2. name as String.

    nameString

  3. isCompleted as Boolean.

    isCompletedBoolean

  4. dueDate, createdAt, updatedAt as Date.

    dueDatecreatedAtupdatedAtDate

Also to help us later when writing the model to dynamoDB dictionary, let’s create a struct named DynamoDBField inside Todo struct. In this case, we just need to provide the key for each of the property using static constant.

为了在以后将模型写入dynamoDB字典时为我们提供帮助,让我们在Todo结构中创建一个名为DynamoDBField结构。 在这种情况下,我们只需要使用静态常量为每个属性提供键。

public struct Todo: Codable {
public let id: String
public let name: String
public let isCompleted: Bool
public var dueDate: Date?
public var createdAt: Date?
public var updatedAt: Date?

public struct DynamoDBField {
static let id = "id"
static let name = "name"
static let isCompleted = "isCompleted"
static let dueDate = "dueDate"
static let createdAt = "createdAt"
static let updatedAt = "updatedAt"
}
}

建筑公用事业ISO8601日期格式 (Building Utils ISO8601 Date Formatter)

Let’s create a new file name Utils.swift, we’ll use this to store the date formatter using ISO8601 format using the static constant inside the Utils struct. As DynamoDB doesn’t provide support to store date as data type, we need to convert the date to the ISO8601 string using the formatter and store the date as string.

让我们创建一个新文件名Utils.swift ,我们将使用Utils结构内部的静态常量使用ISO8601格式存储日期格式程序。 由于DynamoDB不支持将日期存储为数据类型,因此我们需要使用格式化程序将日期转换为ISO8601字符串并将日期存储为字符串。

```
public struct Utils {

public static let iso8601Formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
}extension Date {

var iso8601: String {
Utils.iso8601Formatter.string(from: self)
}
}

Below, let’s create a simple extension for Date to convert the instance to iso8601 string using computed property. In this case, we just need to use Utils date formatter to convert to the date using the string(fromDate:) method passing self as the parameter.

在下面,让我们为Date创建一个简单的扩展,以使用computed property将实例转换为iso8601 string 。 在这种情况下,我们只需要使用Utils日期格式化程序,就可以使用将self作为参数的string(fromDate:)方法转换为日期。

用APIError表示错误 (Representing Error with APIError)

Next, create a new file named APIError. We declare the APIError as enum that conforms to Swift Error protocol. Let’s declare 3 cases:

接下来,创建一个名为APIError的新文件。 我们将APIError声明为符合Swift Error协议的enum 。 让我们声明3种情况:

  1. decodingError

    decodingError

  2. requestError

    requestError

  3. todoNotFound

    todoNotFound

Todo模型扩展,用于DynamoDB项目的编码和解码 (Todo Model Extension For Encoding and Decoding of DynamoDB Item)

Next, create a new file named Todo+DynamoDB.swift. In this file, we’ll create an extension for Todo that will help us to convert Todo instance to dynamoDB dictionary. This will be used when we want to create and update item into DynamoDB. Make sure to import DynamoDB at the top of the source file.

接下来,创建一个名为Todo+DynamoDB.swift的新文件。 在此文件中,我们将为Todo创建扩展名,以帮助我们将Todo实例转换为dynamoDB字典。 当我们要创建项目并将其更新到DynamoDB中时,将使用此方法。 确保在源文件的顶部导入DynamoDB。

The dictionary uses String as the key and DynamoDB.AttributeValue as the value. We’ll use the DynamoDBField constant that we have declared before inside Todo Struct as the key. Then, we can initialize DynamoDB.AttributeValue instance passing the correct data type, for string it will be s: and boolean is bool:. Make sure to convert the Date into the String before putting it into the dictionary.

字典使用String作为键,并使用DynamoDB.AttributeValue作为值。 我们将使用在Todo Struct内部之前声明的DynamoDBField常量作为键。 然后,我们可以初始化DynamoDB.AttributeValue实例,并传递正确的数据类型,对于字符串,它将为s: ,布尔值为bool: DynamoDB.AttributeValue 在将Date放入字典之前,请确保将Date转换为String

Next, we also need to create an initializer that accepts DynamoDB Dictionary to initialize Todo instance. This will be used later when we retrieve todo items from DynamoDB SDK.

接下来,我们还需要创建一个initializer接受DynamoDB字典初始化的Todo实例。 当我们从DynamoDB SDK检索待办事项时,将使用此方法。

In this case, using the guard statement, we make sure all the properties exists in the dictionary and can be casted to the actual data type before we assign them to the properties. If one of them is not exists or the data type is incompatible, we throw a DecodingError.

在这种情况下,使用guard语句,我们确保所有属性都存在于字典中,并且可以在将它们分配给属性之前将其强制转换为实际的数据类型。 如果其中之一不存在或数据类型不兼容,则抛出DecodingError

构建Todo服务以与AWS DynamoDB SDK进行交互 (Building The Todo Service to Interact with AWS DynamoDB SDK)

Let’s move on to create TodoService, this service has the responsibility to interact with AWSDynamoDB SDK to get list of items and also to read, create, update, and delete a single item.

让我们继续创建TodoService ,此服务负责与AWSDynamoDB SDK交互以获取项目列表,以及读取,创建,更新和删除单个项目。

Create a new file named TodoService.swift file and import AWS DynamoDB at the top of the source file. Declare TodoService class, we’ll need 2 instance property. First is the instance of DynamoDB itself, the second one is the tableName of the todo item in AWS. We create an initializer to inject those 2 properties.

创建一个名为TodoService.swift文件的新文件,然后在源文件顶部导入AWS DynamoDB。 声明TodoService class ,我们需要2个实例属性。 第一个是DynamoDB本身的实例,第二个是AWS中todo项的tableName 。 我们创建一个初始化器来注入这两个属性。

获取待办事项列表 (Get Todos List)

Next, create a new method named getAllTodos that returns an EventLoopFuture of Todo Array. In the implementation, we need to create the DynamoDB ScanInput instance passing the tableName. Next, we can use the dynamoDB scan method passing the input. We’re going to chain the ScanOutput to todos array using the FlatMapThrowing operator, if you are familiar with Javascript promise pattern, you can think of this as the then . In case of this, as the mapping can throw an error, we need to use FlatMapThrowing operator.

接下来,创建一个名为getAllTodos的新方法,该方法返回Todo ArrayEventLoopFuture 。 在实现中,我们需要创建传递tableName的DynamoDB ScanInput实例。 接下来,我们可以使用dynamoDB扫描方法传递输入。 我们要去chainScanOutput使用到待办事项阵列FlatMapThrowing运营商,如果你熟悉JavaScript promise的模式,你可以认为这为then 。 在这种情况下,由于映射可能会throw错误,因此我们需要使用FlatMapThrowing运算符。

获取单个待办事项 (Get Single Todo Item)

Let’s create the method to read a single item given an ID of the Todo. We give it a name of getTodo and pass id of type String as single parameter. This will return an EventLoopFuture of Todo. In the implementation, we use the DynamoDB’s GetItemInput passing the key, which is the dictionary containing the id key and DynamoDB Attribute value of String, we also need to pass the tableName. Then, we can use the GetItem passing the input as the parameter. We use FlatMapThrowing to convert the GetItemOutput to the Todo instance passing the dictionary from the item, also if the output’s item is nil, we’ll throw a TodoNotFound APIError.

让我们创建一种方法来读取给定Todo ID的单个项目。 我们给它命名为getTodo ,并将String类型的id作为单个参数传递。 这将返回TodoEventLoopFuture 。 在实现中,我们使用DynamoDB的GetItemInput传递key ,该key是包含id keyDynamoDB Attribute value of String的字典,我们还需要传递tableName 。 然后,我们可以使用GetItem传递输入作为参数。 我们使用FlatMapThrowing的转换GetItemOutputTodo instance通过字典从项目,此外,如果输出的产品nil ,我们会扔一个TodoNotFound APIError

创建待办事项 (Create Todo)

For creating todo, create a new method named createTodo with a single parameter of Todo Model, the return type is EventLoopFuture of Todo. In the implementation, we copy the Todo struct to a new variable, then initialize current date. Then, we assign the updatedAt and createdAt property with the date. Next, we create a DynamoDB’s PutItemInput passing the todo dynamoDB dictionary using the computed property we created before as well as the tableName. At last we invoke putItem method on the DB passing the input. In this case, we can just return the instance of Todo.

要创建待办事项,请使用一个Todo Model参数创建一个名为createTodo的新方法,返回类型为Todo的EventLoopFuture 。 在实现中,我们copy Todo结构copy到新变量,然后初始化当前日期。 然后,我们分配updatedAtcreatedAt与日期属性。 接下来,我们使用之前创建的计算属性以及tableName创建一个传递todo dynamoDB字典的DynamoDB的PutItemInput 。 最后,我们在传递输入的DB上调用putItem方法。 在这种情况下,我们可以只返回Todo的实例。

更新待办事项 (Update Todo)

For updating Todo, create a new method named updateTodo with a single parameter of Todo Model, the return type is EventLoopFuture of Todo. Create a new variable to copy the Todo struct instance, then we just assign the updatedAt with current Date. Implementation of UpdateItemInput is quite complex compared to CreateItemInput. We’ll need to create the expressionAttributeNames Array containing the keys we want to update, then we create the expressionAttributeValues Array which are the values we want to update. Pass the key, which is the ID, returnValues to allNew, then make sure to pass the tableName, at last we use the update expression literal passing the placeholder attribute names and values we have created. At last, we can use the updateItem passing the input, then using FlatMap, we invoke the getTodo item passing the ID to return a EventLoopFuture of Todo.

要更新Todo,请使用Todo Model的单个参数创建一个名为updateTodo的新方法,返回类型为Todo的EventLoopFuture 。 创建一个新变量以copy Todo struct实例,然后我们将updatedAt分配给当前Date。 与CreateItemInput相比, UpdateItemInput实现非常复杂。 我们需要创建包含要更新的键的expressionAttributeNames Array,然后创建expressionAttributeValues Array,它们是我们想要更新的值。 将IDreturnValues的键传递给allNew ,然后确保传递tableName ,最后,我们使用update expression literal传递所创建的placeholder attribute names and values 。 最后,我们可以使用updateItem传递输入,然后使用FlatMap ,调用传递IDgetTodo项以返回Todo的EventLoopFuture

删除待办事项 (Deleting Todo)

At last, to delete an item, we need to create deleteTodo method passing the id of string as single parameter. The return type of this will be an EventFuture of Void. In the implementation, create DynamoDB deleteItemInput passing the key and tableName. At last, we invoke the db’s deleteItemMethod passing the input. Using map we return a void closure.

最后,要删除项目,我们需要创建deleteTodo方法,将id of stringid of string作为单个参数传递。 此类型的返回类型将是EventFuture of Void 。 在实现中,创建传递keytableName DynamoDB deleteItemInput 。 最后,我们通过输入来调用数据库的deleteItemMethod 。 使用map我们返回一个void closure

That’s it for the TodoService class. With this, we’ll be able to perform CRUD operation to DynamoDB! Let’s move on to create our LambdaHandler!

TodoService类就是这样。 这样,我们将能够对DynamoDB执行CRUD操作! 让我们继续创建我们的LambdaHandler

构建TodoLambdaHandler来处理CRUD操作 (Building The TodoLambdaHandler to handle CRUD Operation)

Create a new file named TodoLambdaHandler.swift. We need to import several frameworks into the source code.

创建一个名为TodoLambdaHandler.swift的新文件。 我们需要将几个框架导入源代码。

import Foundation
import AWSLambdaEvents
import AWSLambdaRuntime
import AsyncHTTPClient
import NIO
import AWSDynamoDB

First, let’s declare the TodoLambdaHandler as a struct that implements EventLambdaHandler Protocol. The protocol itself used associatedtype for the event Input and the response Output. In our case, we’re going to use APIGateway Request for the input event and APIGateway Response for the output response. There are several other options you can explore such as S3, SQS, or DynamoDB events.

首先,让我们将TodoLambdaHandler声明为实现EventLambdaHandler协议的struct 。 协议本身将associatedtype用于事件Input和响应Output 。 在本例中,我们将使用APIGateway Requestinput event并使用APIGateway Responseoutput response 。 您可以探索其他几个选项,例如S3,SQS或DynamoDB事件。

struct TodoLamdaHandler: EventLoopLambdaHandler {   typealias In = APIGateway.Request
typealias Out = APIGateway.Response let db: AWSDynamoDB.DynamoDB
let todoService: TodoService
let httpClient: HTTPClient
}

DynamoDB,HTTP客户端和TodoService的初始化 (Initialization of DynamoDB, HTTP Client, and TodoService)

Next, we need to create the initializer that accepts the Lambda.Initialization context, basically we need to initialize the DynamoDB instance and TodoService in the implementation.

接下来,我们需要创建一个接受Lambda.Initialization context的初始化程序,基本上,我们需要在实现中初始化DynamoDB实例和TodoService

First let’s create HTTPClient instance, we need to pass this when initializing DynamoDB later. Declare the timeout variable and initialize it with HTTPClient.Configuration.Timeout passing 30 seconds to both connect and read parameters. Next, lets declare the httpClient variable and initialize HTTPClient passing the .shared with the current context eventLoop as the eventLoopGroupProvider, then for the configuration, we initialize HTTPClient.Configuration passing the timeout variable we created before.

首先让我们创建HTTPClient实例,稍后在初始化DynamoDB时需要传递此实例。 声明超时变量,并使用HTTPClient.Configuration.Timeout对其进行初始化,将30 seconds传递给connect and read参数。 接着,让声明httpClient变量和初始化HTTPClient传递.shared与当前上下文eventLoop作为eventLoopGroupProvider ,那么对于该结构,我们初始化HTTPClient.Configuration经过timeout我们之前创建的变量。

Next, we need to retrieve the name of the table for our DynamoDB todo item, we’ll be storing the TODOS_TABLE_NAME, AWS_REGION, and _HANDLER as the environment variables when we we deploy our function to AWS Lambda.

接下来,我们需要检索DynamoDB todo项的表名,当我们将函数部署到AWS Lambda时,将存储TODOS_TABLE_NAMEAWS_REGION_HANDLER作为environment variables

To retrieve the environment variable, we can use Lambda.env static method passing the name of the variable we want to retrieve from the environment.

要检索环境变量,可以使用Lambda.env静态方法传递要从环境中检索的变量的名称。

Declare the tableName constant and pass the string of TODOS_TABLE_NAME as the parameter.

声明tableName常量,并将TODOS_TABLE_NAME的字符串作为参数传递。

For the region, we pass AWS_REGION as the parameter, then using the value, we initialize the Region enum passing it to the rawValue parameter, if it doesn’t exists, we provide a default fallback region which is us-west-2 located at Oregon, US.

对于区域,我们传递AWS_REGION作为参数,然后使用该值,初始化Region枚举,将其传递给rawValue参数,如果不存在,我们提供default fallback区域,该区域位于us-west-2美国俄勒冈州。

Next, we need to initialize the AWSDynamoDB instance. Declare the db constant and using DynamoDB initializer we pass the region and the httpClientProvider.

接下来,我们需要初始化AWSDynamoDB实例。 声明db常量,并使用DynamoDB初始化程序传递区域和httpClientProvider

For the TodoService, we can initialize it passing the instance of the db and the tableName.

对于TodoService ,我们可以通过db实例和tableName对其进行初始化。

At last, we assign all the property into the instance properties so we can reference to them later. That’s it for the initialization! we have the DB instance and TodoService to perform the CRUD handling operation.

最后,我们将所有属性分配给实例属性,以便稍后引用它们。 初始化就这样! 我们有数据库实例和TodoService来执行CRUD处理操作。

使用处理程序枚举处理CRUD操作 (Handling CRUD Operation with Handler Enum)

There is one required method we need to implement acting as the entry-point when handling the request into our app. It is handle(context:event:)->EventLoopFuture. This will be invoked passing the context and the request API Gateway event containing the HTTP payload. The return type expected is EventLoopFuture API Gateway response which is the representation of the HTTP response we want to return to the client.

处理对我们应用程序的请求时,我们需要实现一种必需的方法,作为入口点。 它是handle(context:event:)->EventLoopFuture 。 将通过上下文和包含HTTP payloadrequest API Gateway事件来调用此方法。 预期的返回类型是EventLoopFuture API Gateway response ,它是我们要返回给客户端的HTTP response的表示。

As we are going to use a single binary to perform all the CRUD operations, we need to be able to know the type of the operation we need to perform when user hits our API. To do this, we need to create an enum named Handler. Basically, this enum represents all the supported operations in our API.

由于我们将使用single binary执行所有CRUD操作,因此我们需要能够知道用户点击我们的API时需要执行的操作类型。 为此,我们需要创建一个名为Handlerenum 。 基本上,该枚举代表了我们API中所有受支持的操作。

Create a new file named Handler inside Model folder. Import AWSLambdaRuntime at the top, and then declare enum Handler with type of String. Our API supports five different operations, create, update, delete, read, and list. To get the handler value, we’ll declare a static computed property named current that returns the handler. We’ll retrieve the handler from the environment variable named _HANDLER, we will set this environment variable for each of the operation when we deploy our function later using Serverless framework.

Model文件夹中创建一个名为Handler的新文件。 在顶部导入AWSLambdaRuntime ,然后声明String类型的枚举Handler。 我们的API支持五种不同的操作,即create, update, delete, read, and list 。 为了获得处理程序的值,我们将声明一个名为current的静态计算属性,该属性返回处理程序。 我们将从名为_HANDLER的环境变量中检索处理程序,稍后在使用无服务器框架部署函数时,将为每个操作设置此环境变量。

enum Handler: String {

case create
case update
case delete
case read
case list

static var current: Handler? {
guard let handler = Lambda.env("_HANDLER") else {
return nil
}
return Handler(rawValue: handler)
}
}

API网关请求和响应扩展 (Extension For API Gateway Request And Response)

Before implementing the handler method, let’s create a helper extension for the APIGateway Request and Response that will help us to decode the request into the Model and encode the model into the response as JSON string.

在实现处理程序方法之前,让我们为APIGateway Request and Response创建一个帮助程序扩展,它将帮助我们将请求decodeModel ,并将模型encodeJSON字符串。

Create a new folder named extensions, then create a new file named APIGateway+Extension.swift inside. At the top import Foundation and AWSLambdaEvents.

创建一个名为extensions的新文件夹,然后在其中创建一个名为APIGateway+Extension.swift的新文件。 在顶部导入FoundationAWSLambdaEvents

First, let’s declare the extension for the APIGateway.Request. We declare one helper method that will help us to decode the JSON body of the request to a Decodable type using generic placeholder. Let’s declare the jsonDecoder static constant and set the date decoding strategy to custom formatter passing the ISO8601 date formatter from the Utils struct.

首先,让我们声明APIGateway.Request的扩展名。 我们声明了一个辅助方法,该方法将帮助我们使用generic占位符将请求的JSON主体解码为Decodable类型。 让我们声明jsonDecoder静态常量,并设置日期格式传递解码策略来定制ISO8601 date formatter从utils的结构。

In the bodyObject implementation, using the if let statement, we check whether the body data exists, if not we throw a Request Error. Then, using the JSON decoder, we just decode the type passing the jsonData, and finally return the decoded instance.

bodyObject实现中,使用if let语句检查主体数据是否存在,如果不存在,则抛出Request Error 。 然后,使用JSON decoder ,我们仅解码传递jsonData的类型,最后返回decoded实例。

Next, let’s create the helper extension for APIGateway Response. Let’s begin by declaring the jsonEncoder static constant. Similar to the JSONDecoder, we set the dateDecodingStrategy to use custom ISO8601 date formatter.

接下来,让我们为APIGateway Response创建帮助程序扩展。 让我们首先声明jsonEncoder静态常量。 类似于JSONDecoder ,我们设置dateDecodingStrategy使用自定义的ISO8601日期格式。

Next, lets’ declare the constant for the defaultHeaders. The value itself is a dictionary with type of String as the key and value. This will be used to set the HTTP response headers to allow CORS when invoked from a website and to allow all HTTP methods.

接下来,让我们声明defaultHeaders的常量。 该值本身是一个字典,以String类型为键和值。 这将用于设置HTTP response headers ,以便从网站调用时允许CORS ,并允许所有HTTP方法。

Let’s move on to create a new initializer that accepts error and AWSLambdaEvents.HTTPResponseStatus. In this case we just invoke the initializer passing the status code, then pass the defaultHeaders to the HTTP headers, also in the body we pass hardcoded JSON string with the key of error and string value of the error. We’ll use this later when we want to return an error as the response.

让我们继续创建一个新的初始化器,该初始化器接受error和AWSLambdaEvents.HTTPResponseStatus 。 在这种情况下,我们只调用传递status codeinitializer status code ,然后将defaultHeaders传递给HTTP标头,同样在主体中,我们传递带有错误键和错误字符串值的hardcoded JSON字符串。 当我们要返回错误作为响应时,将在以后使用它。

The second initializer accepts an encodable object using generic placeholder and the HTTPResponseStatus. This will be helpful later when we want to return instance of Todo or Todo array as they both conforms to Codable protocol. In the implementation, we encode the instance using JSONEncoder and assign the String of the data to the body variable using UTF-8 encoding. At last, we invoke the initializer passing the status code, defaultHeaders, and the body.

第二个initializer使用generic占位符和HTTPResponseStatus接受可encodable对象。 当我们想返回Todo或Todo数组的实例时,这将很有帮助,因为它们都符合Codable协议。 在实现中,我们使用JSONEncoder编码实例,并使用UTF-8编码将数据的String分配给主体变量。 最后,我们调用初始化器,传递状态码,defaultHeaders和主体。

At the bottom, create a new Struct named EmptyResponse that conforms to Encodable. The implementation is empty, as this will be used when we want to return a response with empty body such as when deleting a Todo item.

在底部,创建一个新的Struct,名为EmptyResponse ,它符合Encodable 。 该实现是空的,因为当我们要返回带有空正文的响应时(例如删除Todo项时),将使用该实现。

实现Todo Lambda处理程序 (Implementing Todo Lambda Handler)

Finally, let’s move back to the TodoLambdaHandler to implement the handler method!

最后,让我们回到TodoLambdaHandler来实现handler方法!

使用枚举处理程序枚举作为主处理程序传入事件 (Using Enum Handler Enum as Main Handler Incoming Event)

First, let’s use a guard statement to get the current type of the handler operation using the Handler.current static property, if it is not exits, we just return a resolved successful eventLoopFuture passing the APIGateway.Response instance with APIError and badRequest HTTP Status Type. This will returns the response with 40` as the HTTP Status code containing the error message in the body.

首先,让我们使用guard语句通过Handler.current静态属性获取处理程序操作的当前类型,如果未退出,我们只需返回已resolved successful eventLoopFuture并通过APIGateway.Response实例APIErrorbadRequest HTTP状态类型。 这将返回与响应40 `作为包含在体内的错误消息的HTTP状态代码。

Then, we use the switch statement on the enum instance to handle all the possible operations. We’ll create a method to handle each of the operation. All of them accept Lambda.Context and APIGateway.Request, then returns EventLoopFuture of APIGateway.Response.

然后,我们在枚举实例上使用switch语句来处理所有可能的操作。 我们将创建一个方法来处理每个操作。 它们都接受Lambda.ContextAPIGateway.Request ,然后返回APIGateway.Response的APIGateway.Response

处理创建待办事项 (Handling Create Todo)

First, let’s declare the handleCreate method to handle creating single Todo Item. Using the guard statement, we decode the request body to Todo instance, if it doesn’t exists, we return a resolved EventLoopFuture passing the APIGateway.Response of RequestError and badRequest httpStatus. Next, we invoke TodoService’s createTodo method passing the todo instance. As this returns a Future of Todo, we need to map it to APIGateway.Response using the map operator. In the closure body, we initialize the APIGateway.Response passing the Todo instance and ok as the HTTPResponseStatus. This will encode the instance into the JSON data, then put in the response body and set the HTTP status code to 200.

首先,让我们声明handleCreate方法来处理创建单个Todo Item的过程。 使用保护声明,我们请求主体进行解码,以藤例如,如果不存在的话,我们返回一个解决EventLoopFuture传递APIGateway.ResponseRequestErrorbadRequest则httpStatus。 接下来,我们通过传递todo实例调用TodoService的createTodo方法。 当这返回“ Future的待办事项”时,我们需要使用map运算符将其mapAPIGateway.Response 。 在闭包主体中,我们初始化APIGateway.Response并传递Todo实例, APIGateway.Response将其okHTTPResponseStatus 。 这会将实例编码为JSON数据,然后放入响应正文并将HTTP状态代码设置为200。

Also in case there is an error in the eventLoop chain, we need to catch it and return the appropriate error. Let’s declare a method named catchError that accept a Lambda context and error as the parameter, then return EventLoopFuture of APIGateway.Response. In the body, we just need to initialize the APIGateway.Response and pass the error, then return the resolved future passing the response.

同样,如果eventLoop链中有错误,我们需要捕获它并返回适当的错误。 让我们声明一个名为catchError的方法,该方法接受Lambda上下文和error作为参数,然后返回EventLoopFutureAPIGateway.Response 。 在主体中,我们只需要初始化APIGateway.Response并传递错误,然后返回已解析的将来传递的响应。

Going back to create method, to catch the error, we can use the flatMapError operator. This will be invoked if there is an error thrown in one of the upstream, think of this as the catch error promise in Javascript. In this case, we can just invoke the catchError method we created before to return the APIGateway.Response.

回到create方法,要捕获错误,我们可以使用flatMapError运算符。 如果upstream之一抛出错误,则将调用此方法,将其视为Javascript中的catch error promise 。 在这种情况下,我们可以调用之前创建的catchError方法来返回APIGateway.Response

处理读待办事项 (Handling Read Todo)

Next, let’s create the handleRead method. In the implementation, we check if the pathParameters dictionary contains value with key of id, if not we just return resolved promise of response with request error and http status 400. Then, we just need to invoke todoService’s getTodo method passing the value of id. Using map operator we transform the Todo instance to Response passing the todo instance to be encoded in the HTTP Body and set the status code to 200.

接下来,让我们创建handleRead方法。 在实现中,我们检查pathParameters词典是否包含带有id关键字的值,否则,我们只返回带有请求错误和http状态400的已解决响应承诺。然后,我们只需要调用todoService的getTodo方法并传递id的值即可。 使用map运算符,我们将Todo实例转换为Response,并传递要在HTTP正文中进行编码的todo实例,并将状态代码设置为200。

处理更新待办事项 (Handling Update Todo)

To update a todo item, let’s create the handleUpdate method. Just like the handleCreate method, using the guard statement, we decode the http body to Todo instance. If fails, we just return resolved promise with response containing requestError and 400 as the http status code. Then, we invoke todo’s service updateTodo method passing the updatedTodo item. Using the map operator, we transform the result of the todo item to APIGateway passing the todo instance to be encoded as JSON in the HTTP body, and set the status code to 200.

要更新待办事项,我们创建handleUpdate方法。 就像handleCreate方法一样,我们使用guard语句将http正文decodeTodo实例。 如果失败,我们只返回已解决的promise,响应中包含requestError和400作为http状态代码。 然后,我们调用todo的服务updateTodo方法,并传递updatedTodo项目。 使用map运算符,我们将todo项的结果转换为APIGateway并传递todo实例,以在HTTP正文中将其编码为JSON,并将状态代码设置为200。

处理删除待办事项 (Handle Delete Todo)

Next, let’s create the handleDelete for deleting a todo item. Just like handleRead method, we need to get the id to delete from the pathParameters passing id as the key to the dictionary. After that, we just invoke todoService’s deleteTodo method passing the id. In this case, we just need to return APIGateway response with empty body and status code of 200.

接下来,让我们创建handleDelete来删除待办事项。 就像handleRead方法一样,我们需要获取id以将id作为字典的键从pathParameters删除。 在那之后,我们只是调用传递ID的todoService的deleteTodo方法。 在这种情况下,我们只需要返回带有空主体和状态码200的APIGateway响应。

处理待办事项清单 (Handle List Todos)

The last handler, is the handleList method. In this handler, we just invoke todoService’s getAllTodos method, then transform the result of the Todo Array into APIGateway Response passing the array to be encoded as JSON into the HTTP body and set the status code as 200.

最后一个处理程序是handleList方法。 在此处理程序中,我们仅调用todoService的getAllTodos方法,然后将Todo数组的结果转换为APIGateway Response,将要编码为JSON的数组传递到HTTP正文中,并将状态代码设置为200。

That’s it for the TodoLambdaHandler, now let’s put this into main.swift where we will run the Lambda passing the handler.

TodoLambdaHandler就是这样,现在将其放入main.swift ,在此我们将传递通过处理程序的Lambda。

Lambda.run(TodoLamdaHandler.init)

We have completed building the app, now let’s build the app and archive the app into a Zip file so it can be uploaded to AWS Lambda!

我们已经完成了应用程序的构建,现在让我们构建应用程序并将其存档到一个Zip文件中,以便可以将其上传到AWS Lambda!

使用Docker Swift Amazon Linux 2 Distro构建和打包 (Building and Packaging Using Docker Swift Amazon Linux 2 Distro)

Before we begin the process, make sure to install Docker into your operating system. Check the link to install docker from the description if you haven’t installed. We’re going to use Docker Container using official Swift Amazon Linux 2 Image to build the release, and package the binary into the bootstrap file required by the AWS Lambda to run the function.

在开始该过程之前,请确保将Docker安装到您的操作系统中。 如果尚未安装,请从说明中检查链接以安装docker。 我们将使用Docker Container和官方Swift Amazon Linux 2 Image来构建发行版,并将二进制文件打包到AWS Lambda所需的引导程序文件中,以运行该功能。

Let’s follow the instruction from Fabian Fett’s website. He is one of the contributor of the Swift AWS Lambda library. He posted a great tutorial on building and packaging Swift into the zip file ready to be used in AWS.

让我们按照Fabian Fett网站上的说明进行操作。 他是Swift AWS Lambda库的贡献者之一。 他发布了一篇很棒的教程,介绍如何将Swift构建和打包到zip文件中,以便在AWS中使用。

创建Dockerfile (Creating The Dockerfile)

In this step, we need to create a Dockerfile on the project directory. So, let’s open terminal and navigate to the project directory. Then, create a new file named Dockerfile. Open it in your editor, then copy and paste into the file.

在此步骤中,我们需要在项目目录上创建一个Dockerfile 。 因此,让我们打开终端并导航到项目目录。 然后,创建一个名为Dockerfile的新文件。 在编辑器中将其打开,然后复制并粘贴到文件中。

FROM swiftlang/swift:nightly-amazonlinux2

RUN yum -y install \
git \
libuuid-devel \
libicu-devel \
libedit-devel \
libxml2-devel \
sqlite-devel \
python-devel \
ncurses-devel \
curl-devel \
openssl-devel \
tzdata \
libtool \
jq \
tar \
zip

This will use the the Swift Nightly image for Amazon Linux 2 from SwiftLang docker repository, then add the required dependencies to build and run Swift.

这将使用SwiftLang docker存储库中的Amazon Linux 2的Swift Nightly映像,然后添加所需的依赖项以构建和运行Swift。

Next, let’s build the container using the Dockerfile. Let’s give it a name of swift-lambda-builder. Type the following syntax.

接下来,让我们使用Dockerfile构建容器。 让我们给它命名为swift-lambda-builder 。 输入以下语法。

docker build -t swift-lambda-builder .

从Docker容器构建应用 (Building The App from Docker Container)

Wait after the container are created, then let’s build the binary from the Docker container using this syntax.

在创建容器之后等待,然后让我们使用此语法从Docker容器构建二进制文件。

docker run \
--rm \
--volume "$(pwd)/:/src" \
--workdir "/src/" \
swift-lambda-builder \
swift build --product TodoAPI -c release

This will run the swift-lambda-builder container and set the current directory as the working directory, then execute swift build command passing the TodoAPI as the product flag and compile it in release mode.

这将运行swift-lambda-builder容器并将当前目录设置为工作目录,然后执行swift build命令,将TodoAPI作为产品标志传递,并在发布模式下进行编译。

创建脚本以存档应用程序和依赖项 (Creating Script to Archive App and Dependencies)

Next, let’s create package the executables for the deployment. Basically, we need to create the bootstrap file and symlink all the executable, we also need to copy several Swift runtime library into the folder. To help us do this, let’s create shell script. Create a new folder called scripts, then inside the folder, create a new shell file named package.sh. Copy and paste the code into the file, replace SquareNumber with TodoAPI.

接下来,让我们创建用于部署的可执行文件的程序包。 基本上,我们需要创建bootstrap文件并symlink all the executable ,我们还需要copy几个Swift运行时库copy到该文件夹​​中。 为了帮助我们做到这一点,让我们创建shell script 。 创建一个名为scripts的新文件夹,然后在该folder内创建一个名为package.sh的新外壳文件。 将代码复制并粘贴到文件中,用SquareNumber替换TodoAPI

#!/bin/bashset -euexecutable=$1target=.build/lambda/$executable
rm -rf "$target"
mkdir -p "$target"
cp ".build/release/$executable" "$target/"
cp -Pv \
/usr/lib/swift/linux/libBlocksRuntime.so \
/usr/lib/swift/linux/libFoundation*.so \
/usr/lib/swift/linux/libdispatch.so \
/usr/lib/swift/linux/libicu* \
/usr/lib/swift/linux/libswiftCore.so \
/usr/lib/swift/linux/libswiftDispatch.so \
/usr/lib/swift/linux/libswiftGlibc.so \
"$target"
cd "$target"
ln -s "$executable" "bootstrap"
zip --symlinks lambda.zip *

Don’t forget to set the file as executable using

不要忘记使用以下命令将文件设置为可执行文件

sudo chmod +x package.sh

Navigate back to project directory and run this syntax.

导航回到项目目录并运行此语法。

docker run \
--rm \
--volume "$(pwd)/:/src" \
--workdir "/src/" \
swift-lambda-builder \
scripts/package.sh TodoAPI

Just like before, this will run the swift-lambda-builder container, then execute package.sh inside the scripts folder.

和之前一样,这将运行swift-lambda-builder container ,然后在scripts文件夹中执行package.sh

We can check the result of the final zipped package, by navigating to build/lambda/TodoAPI. The Lambda.zip file should exists in the directory.

我们可以通过导航到build/lambda/TodoAPI来检查最终zipped包的结果。 Lambda.zip文件应存在于目录中。

That’s it for packaging! now let’s move on to the next step, where we will use Serverless framework to handle deployment of our function to AWS.

包装就是这样! 现在,我们继续下一步,使用Serverless framework将功能deployment到AWS。

使用无服务器框架进行配置和部署 (Provisioning And Deployment with Serverless Framework)

To begin, please make sure you have node.js installed in your system, you can install using the installer from the official website or using brew package manager.

首先,请确保已在系统中安装了node.js ,可以使用官方网站上的安装程序或brew软件包管理器进行安装。

After that run:

在那之后运行:

sudo npm install -g serverless

I assume you have already setup the AWS credentials in your user directory ~/.aws/credentials. If not, please create an IAM role from AWS console with required privileges, in my case, i usually provide full access to provision resources in my main machine.

我假设您已经在用户目录~/.aws/credentials设置了AWS ~/.aws/credentials 。 如果不是,请使用required privileges从AWS控制台创建一个IAM role ,在我的情况下,我通常提供对主机中预配置资源的完全访问权限。

To use serverless, we just need to create a Serverless yaml file in the project directory. This YAML contains all the declaration we need to provision the service. Let’s create serverless.yml file in our project directory.

要使用无服务器,我们只需要在项目目录中创建一个无服务器yaml文件。 该YAML包含我们提供服务所需的所有声明。 让我们在项目目录中创建serverless.yml文件。

Open it with your code editor, be very careful with indentation when editing a YAML file, as it uses indentation to structure the data. It is preferred to use spaces instead of tabs when editing YAML file. In this case i use 2 spaces for the indentation.

使用代码编辑器打开它,在编辑YAML文件时请小心使用缩进,因为它使用缩进来构造数据。 在编辑YAML文件时,最好使用空格而不是制表符。 在这种情况下,我使用2个空格作为缩进。

At the top, let’s declare the service, you should provide your own unique value here. In this case, i named it as alf-todoapi. Next, declare the package, inside the package, we have one key, artifact. Let’s put the directory of where our Lambda.zip is located inside the build folder. This will be used for deploying to AWS later.

在顶部,让我们声明service ,您应该在此处提供自己的unique值。 在这种情况下,我将其命名为alf-todoapi 。 接下来,声明package ,在package内部,我们有一个键artifact 。 让我们将Lambda.zip所在的目录放在build文件夹中。 稍后将用于部署到AWS。

Next, lets’ declare custom key used for referencing resources in this YAML. We’ll have one key which is todosTableName with value of todos-${self:provider.stage}.

接下来,让我们声明用于引用此YAML中的资源的自定义键。 我们将拥有一个键,它是todosTableName ,其值为todosTableName todos-${self:provider.stage}

Next, let’s declare the provider. Inside the provider, set the name to aws and runtime as provided. For stage, we’ll set it as dev, and region to us-west-2. For the `environment`, we have one variable, which is the TODOS_TABLE_NAME and for the value we can retrieve it from the custom.todosTableName we created earlier. Next, let’s declare the IAM role for the functions. For our functions, we only provide 2 IAM role, one is to write logs to CloudWatch, and the other one is to perform CRUD operation to DynamoDB. Other than those 2, our function won’t be able to access other AWS services and resources.

接下来,让我们声明provider 。 在provider内部,根据providername to awsname to aws设置name to awsruntime as provided 。 对于stage ,我们将其设置为dev ,并将regionus-west-2 。 对于`environment`,我们有一个变量,即TODOS_TABLE_NAME ,对于该值,我们可以从custom.todosTableName创建的custom.todosTableName检索它。 接下来,让我们声明这些函数的IAM role 。 对于我们的功能,我们仅提供2个IAM角色,一个是write logs to CloudWatch ,另一个是perform CRUD operation to DynamoDB 。 除此之外,我们的功能将无法访问其他AWS服务和资源。

Next, let’s declare the functions. We have five functions that triggered from HTTP events.:

接下来,让我们声明功能。 我们有五个从HTTP事件触发的功能:

  1. createTodo with handler of create, we set the path to /todos, method to POST, and enable CORS.

    使用create处理程序的createTodo ,我们将路径设置为/todos ,方法设置为POST ,并启用CORS

  2. readTodo with handler of read, set the path to /todos/{id}. method to GET. the id placeholder can be retrieved from the pathParameters dictionary in the event request from API Gateway.

    具有读取处理程序的readTodo ,将路径设置为/todos/{id}GET方法。 可以在API网关发出的事件请求中从pathParameters字典中检索id占位符。

  3. updateTodo with handler of update, set the path to /todos/{id} and method to PUT. Make sure to enable CORS.

    具有更新处理程序的updateTodo ,将路径设置为/todos/{id}并将方法设置为PUT 。 确保启用CORS

  4. deleteTodo with handler of delete, set the path to /todos/{id} and method to DELETE.

    具有删除处理程序的deleteTodo ,将路径设置为/todos/{id}并将方法设置为DELETE

  5. listTodos with handler of list, set the path to /todos and method to GET.

    具有list处理程序的listTodos ,将路径设置为/todos ,将方法设置为GET

The handler value itself can be accessed from the _HANDLER environment variable. We are using that to initialize the handler operation in the code we have created.

可以从_HANDLER环境变量访问处理程序值本身。 我们使用它来初始化我们创建的代码中的处理程序操作。

Next, we need to provision the DynamoDB table resource. We need to put inside the resources. Give it name of TodosTable. The type is AWS::DynamoDB::Table. For the properties, TableName value can be retrieved from the custom.TodosTableName variable. The AttributeDefinition will have one single Attribute Name which is used as the Key for this table. Finally, set the BillingMode as PAY_PER_REQUEST.

接下来,我们需要provision DynamoDB表资源。 我们需要投入resources 。 给它起名字TodosTable 。 类型是AWS::DynamoDB::Table 。 对于属性,可以从custom.TodosTableName变量中检索TableName值。 AttributeDefinition将有一个单一的Attribute Name ,用作此表的Key 。 最后,将BillingMode设置为PAY_PER_REQUEST

That’s it for the Serverless YAML file, you can learn more about Serverless by visiting the website that i provide in description below. Other than AWS, it also supports deployment to Google Cloud Function and Azure Function.

仅用于无服务器YAML文件,您可以通过访问我在下面的描述中提供的网站来了解有关无服务器的更多信息。 除AWS以外,它还支持部署到Google Cloud Function和Azure Function。

To deploy, from the project directory in terminal, we can just type:

要进行部署,可以从终端的项目目录中键入:

sls -v deploy

This will parse the serverless YAML, create the resources on CloudFormation, upload the code to S3 bucket, provision the DynamoDB table, and handle the creation of API Gateway for our function!

这将解析无服务器的YAML,在CloudFormation上创建资源,将代码上传到S3存储桶,提供DynamoDB表,并为我们的功能处理API网关的创建!

Wait until, the deployment has completed. The output will provide us the endpoint that we can use to hit our CRUD API. We can also check the AWS Lambda web dashboard to check the status and logs of our function. Try to use POSTMAN or CURL to hit the endpoint. In my case, i already provided the iOS client app in the completed project repository which you can use to test. It is built with SwiftUI and use CoreData to sync the data.

等到部署完成。 输出将为我们提供可用于访问CRUD API的端点。 我们还可以检查AWS Lambda Web仪表板以检查功能的状态和日志。 尝试使用POSTMAN或CURL命中端点。 就我而言,我已经在完整的项目存储库中提供了iOS客户端应用程序,您可以使用它来进行测试。 它使用SwiftUI构建,并使用CoreData同步数据。

结论 (Conclusion)

That’s if for this tutorial. To summarize, we have learned to build a backend REST API with Swift and DynamoDB as persistence layer in the cloud, then deploy it to AWS Lambda using Serverless framework. There are many other various cases we can use to build serverless app, such image processing after an image has been uploaded to S3 bucket, processing notification from SNS, and many more. Keep exploring, and i hope this video will be helpful to all of you.

如果是本教程的话。 总而言之,我们学习了使用Swift和DynamoDB作为云中的持久层构建后端REST API,然后使用无服务器框架将其部署到AWS Lambda。 我们可以使用许多其他各种情况来构建无服务器应用程序,例如,在将图像上传到S3存储桶后进行图像处理,处理来自SNS的通知等等。 继续探索,希望这段视频对大家都有用。

Until the next one, let’s keep the lifelong learning goes on. Bye!

在下一课之前,让我们继续进行终身学习。 再见!

翻译自: https://medium.com/@alfianlosari/building-swift-serverless-rest-api-with-aws-lambda-dynamodb-58db2302895f

aws dynamodb

 类似资料: