Serverless API using AWS APIGateway, Lambda, and DynamoDB in Swift is like a breeze!
This package provides the code to build a Serverless REST API in Swift based on AWS Lambda, APIGateway and DynamoDB.
The following diagram represents the infrastructure architecture of a CRUD REST Serverless API:
The APIGateway exposes the API interface through endpoints and converts the HTTP requests to APIGatewayV2Request events for the Lambdas. Each Lambda receives events from the APIGateway, decodes the events to extract parameters, operates on a DynamoDB table and returns a response payload to the APIGateway. DynamoDB will be accessed through the Lambdas to persist a key-value pair representing data.
With a single line of code, Breeze implements all the Lambdas required for the CRUD interface converting APIGatewayV2Request to an operation on a DynamoDB table and responding with APIGatewayV2Response to the APIGateway.
Define a Codable
struct or class like the Item
one's in the example and pass it to BreezeLambdaAPI
using the type placeholder.
import Foundation
import BreezeLambdaAPI
import BreezeDynamoDBService
struct Item: Codable {
public var key: String
public let name: String
public let description: String
public var createdAt: String?
public var updatedAt: String?
enum CodingKeys: String, CodingKey {
case key
case name
case description
case createdAt
case updatedAt
}
}
extension Item: BreezeCodable { }
BreezeLambdaAPI<Item>.main()
It's required the Codable
struct or class to conform to the BreezeCodable
protocol:
public protocol BreezeCodable: Codable {
var key: String { get set }
var createdAt: String? { get set }
var updatedAt: String? { get set }
}
The code above is the business logic required inside all the Lambdas.
All you need to do is to decide the struct conforming BreezeCodable
to persist on DynamoDB.
Each lambda will be initialized with a specific _HANDLER
and it will run the code to implement the required logic needed by one of the CRUD functions. The code needs to be packaged and deployed using the referenced architecture.
To package the Lambda is required to create a Swift Package using the following Package.swift
file.
// swift-tools-version:5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "swift-breeze-item-api",
platforms: [
.macOS(.v13),
],
products: [
.executable(name: "ItemAPI", targets: ["ItemAPI"]),
],
dependencies: [
.package(url: "https://github.com/swift-sprinter/Breeze.git", from: "0.1.0"),
],
targets: [
.executableTarget(
name: "ItemAPI",
dependencies: [
.product(name: "BreezeLambdaAPI", package: "Breeze"),
.product(name: "BreezeDynamoDBService", package: "Breeze"),
]
)
]
)
To be executed on a Lambda, the package needs to be built on AmazonLinux2
and deployed.
The API can be deployed on AWS in multiple ways.
Refer to the Example folder to explore a deployment example using the Serverless Framework.
The package contains a command line tool to generate the deployment of the swift package, the serverless.yml
file and the relevant commands to deploy the Lambda code on AWS using the Serverless Framework.
swift run breeze --help
output:
OVERVIEW: Breeze command line
Generate the deployment of a Serverless API using Breeze.
The command generates of the swift package, the `serverless.yml` file and the relevant commands in the target path to deploy the Lambda code on AWS using the Serverless Framework.
USAGE: breeze --config-file <config-file> --target-path <target-path> [--force-overwrite] [-y]
OPTIONS:
-c, --config-file <config-file>
YML configurarion file
-t, --target-path <target-path>
Target path
-f, --force-overwrite Force target path overwrite
-y
-h, --help Show help information.
Define a configuration file with the following format:
service: swift-breeze-rest-item-api
awsRegion: us_east_1
swiftVersion: 5.7.3
swiftConfiguration: release
packageName: BreezeItemAPI
buildPath: build
cors: false
authorizer: #optional
name: appleJWT
type: JWTAuthorizer
issuerUrl: https://appleid.apple.com
audience:
- APP_BUNDLE_IDENTIFIER #Change this with the App BUNDLE_IDENTIFIER
breezeLambdaAPI:
targetName: ItemAPI
itemCodable: Item
itemKey: itemKey
httpAPIPath: /items
dynamoDBTableNamePrefix: items
Configuration parameters:
awsRegion
: AWS RegionswiftVersion
: Swift versionswiftConfiguration
: Swift configuration (debug or release)packageName
: Swift Package namebuildPath
: Swift Package build path where the Lambda executable will be generatedcors
: Enable CORS (default: false)authorizer
: Optional. If defined, the API will be protected by the specified authorizer. The authorizer can be a custom one or a predefined one. APP_BUNDLE_IDENTIFIER
is the App Bundle Identifier of the iOS App that will use the API.
If you don't want to use a custom authorizer, remove the authorizer
section.breezeLambdaAPI
: Breeze Lambda API configuration
targetName
: The name of the target that will be generated by the Swift Package ManageritemCodable
: The name of the Codable
struct or class that will be persisted on DynamoDBitemKey
: The name of the key of the Codable
struct or class that will be persisted on DynamoDBhttpAPIPath
: The path of the APIdynamoDBTableNamePrefix
: The prefix of the DynamoDB table nameThe following command will run using the example configuration file and generate the deployment files in the .build/temp
folder.
swift run breeze -c Sources/BreezeCommand/Resources/breeze.yml -t .build/temp
output:
โ๏ธ Loading configuration file
/Users/andreascuderi/Documents/workspace/Breeze/Sources/BreezeCommand/Resources/breeze.yml
service: swift-breeze-rest-item-api
awsRegion: us_east_1
swiftVersion: 5.7.3
swiftConfiguration: release
packageName: BreezeItemAPI
buildPath: build
cors: false
breezeLambdaAPI:
targetName: ItemAPI
itemCodable: Item
itemKey: itemKey
httpAPIPath: /items
dynamoDBTableNamePrefix: items
๐ Verifing target path
๐งน .build/temp
โ
Target path ready!
๐ Generating project from template
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/SwiftPackage/Package.swift
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/SwiftPackage/Sources/SwiftTarget/main.swift
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/Dockerfile
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/remove.sh
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/.gitignore
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/deploy.sh
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/update.sh
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/Makefile
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/README.md
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/build.sh
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/swagger.json
๐ซ .build/temp/SwiftPackage/Sources/SwiftTarget
๐ฌ .build/temp/SwiftPackage/Sources/ItemAPI
๐ซ .build/temp/SwiftPackage
๐ฌ .build/temp/BreezeItemAPI
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/serverless.yml
๐ /Users/andreascuderi/Documents/workspace/Breeze/.build/temp/serverless-x86_64.yml
โ
Project is ready at target-path
.build/temp
๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต
๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต
๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต
๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต
๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐จ๐จ๐จ๐จ๐จ๐ต๐ต
๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต
๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐ต๐ต๐ต๐จ๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐ต๐ต
๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐ต๐จ๐ต๐ต๐ต๐ต๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต๐จ๐จ๐จ๐จ๐จ๐จ๐ต
๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต๐ต
๐จ Use the following commands to build & deploy
cd .build/temp
./build.sh
./deploy.sh
Follow the instructions to build and deploy the project. For more information about the deployment, please refer to the generated README.md
file.
During the Lambda's initialization, the BreezeLambdaAPI
reads the configuration from the following Environment
variables:
AWS_REGION
: AWS Region_HANDLER
: The handler name specifies the CRUD operation implemented by the Lambda using the following format {executable_name}.{BreezeOperation}
or {BreezeOperation}
enum BreezeOperation: String {
case create
case read
case update
case delete
case list
}
(example: build/RestAPI.create
where build/RestAPI
is the executable name and create
is the BreezeOperation).
DYNAMO_DB_TABLE_NAME
: DynamoDB table name.DYNAMO_DB_KEY
: DynamoDB Primary KeyBreezeLambdaAPI
receives an APIGateway event, extracts the relevant parameters and performs a BreezeOperation
on BreezeDynamoDBService
.
create
Decodes a BreezeCodable
from the APIGatewayV2Request.body
and calls createItem
on BreezeDynamoDBService
.
Returns the created BreezeCodable
.
read
Gets the value of the BreezeCodable.key
from the APIGatewayV2Request.pathParameters
dictionary and calls readItem
on BreezeDynamoDBService
.
Returns the BreezeCodable
if persisted on DynamoDB.
update
Decodes a BreezeCodable
from the APIGatewayV2Request.body
and calls updateItem
on BreezeDynamoDBService
.
Returns the updated BreezeCodable
.
delete
Gets the value of the BreezeCodable.key
from the APIGatewayV2Request.pathParameters
dictionary and calls deleteItem
on BreezeDynamoDBService
.
Returns the BreezeCodable
if persisted on DynamoDB.
list
Gets the value of the exclusiveStartKey
and limit
from the APIGatewayV2Request.pathParameters
dictionary and calls listItems
on BreezeDynamoDBService
.
Returns the ListResponse
containing the items if persisted on DynamoDB.
struct ListResponse<T: Codable>: Codable {
let items: [T]
let lastEvaluatedKey: String?
}
(See SotoDynamoDB documentation for more info *)
link |
Stars: 13 |
Last commit: 2 weeks ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics