Skip to content

Commit 3511a92

Browse files
authored
Update examples for Swift 5.5 (#223)
- Lambda examples use async/await - SwiftUI example uses async/await - Handlers are marked with `@main` - Executables are defined as `.executableTarget` - Examples require Swift 5.5
1 parent 782c0f3 commit 3511a92

File tree

10 files changed

+110
-61
lines changed

10 files changed

+110
-61
lines changed

Examples/LambdaFunctions/Package.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// swift-tools-version:5.2
1+
// swift-tools-version:5.5
22

33
import PackageDescription
44

55
let package = Package(
66
name: "swift-aws-lambda-runtime-samples",
77
platforms: [
8-
.macOS(.v10_13),
8+
.macOS(.v12),
99
],
1010
products: [
1111
// introductory example
@@ -24,16 +24,16 @@ let package = Package(
2424
.package(name: "swift-aws-lambda-runtime", path: "../.."),
2525
],
2626
targets: [
27-
.target(name: "HelloWorld", dependencies: [
28-
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
29-
]),
30-
.target(name: "Benchmark", dependencies: [
27+
.executableTarget(name: "Benchmark", dependencies: [
3128
.product(name: "AWSLambdaRuntimeCore", package: "swift-aws-lambda-runtime"),
3229
]),
33-
.target(name: "ErrorHandling", dependencies: [
30+
.executableTarget(name: "HelloWorld", dependencies: [
31+
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
32+
]),
33+
.executableTarget(name: "ErrorHandling", dependencies: [
3434
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
3535
]),
36-
.target(name: "CurrencyExchange", dependencies: [
36+
.executableTarget(name: "CurrencyExchange", dependencies: [
3737
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
3838
]),
3939
]

Examples/LambdaFunctions/Sources/Benchmark/main.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import NIO
1919
// use this example which is more performant.
2020
// `EventLoopLambdaHandler` does not offload the Lambda processing to a separate thread
2121
// while the closure-based handlers do.
22-
Lambda.run(BenchmarkHandler())
22+
Lambda.run { $0.eventLoop.makeSucceededFuture(BenchmarkHandler()) }
2323

2424
struct BenchmarkHandler: EventLoopLambdaHandler {
2525
typealias In = String

Examples/LambdaFunctions/Sources/CurrencyExchange/main.swift renamed to Examples/LambdaFunctions/Sources/CurrencyExchange/CurrencyExchangeHandler.swift

+24-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,30 @@ import Logging
2323

2424
// MARK: - Run Lambda
2525

26-
Lambda.run { (context: Lambda.Context, _: Request, callback: @escaping (Result<[Exchange], Error>) -> Void) in
27-
let calculator = ExchangeRatesCalculator()
28-
calculator.run(logger: context.logger, callback: callback)
26+
@main
27+
struct CurrencyExchangeHandler: AsyncLambdaHandler {
28+
typealias In = Request
29+
typealias Out = [Exchange]
30+
31+
let calculator: ExchangeRatesCalculator
32+
33+
init(context: Lambda.InitializationContext) async throws {
34+
// the ExchangeRatesCalculator() can be reused over and over
35+
self.calculator = ExchangeRatesCalculator()
36+
}
37+
38+
func handle(event: Request, context: Lambda.Context) async throws -> [Exchange] {
39+
try await withCheckedThrowingContinuation { continuation in
40+
self.calculator.run(logger: context.logger) { result in
41+
switch result {
42+
case .success(let exchanges):
43+
continuation.resume(returning: exchanges)
44+
case .failure(let error):
45+
continuation.resume(throwing: error)
46+
}
47+
}
48+
}
49+
}
2950
}
3051

3152
// MARK: - Business Logic

Examples/LambdaFunctions/Sources/ErrorHandling/main.swift renamed to Examples/LambdaFunctions/Sources/ErrorHandling/ErrorsHappenHandler.swift

+23-15
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,29 @@ import AWSLambdaRuntime
1616

1717
// MARK: - Run Lambda
1818

19-
// switch over the error type "requested" by the request, and trigger such error accordingly
20-
Lambda.run { (context: Lambda.Context, request: Request, callback: (Result<Response, Error>) -> Void) in
21-
switch request.error {
22-
// no error here!
23-
case .none:
24-
callback(.success(Response(awsRequestID: context.requestID, requestID: request.requestID, status: .ok)))
25-
// trigger a "managed" error - domain specific business logic failure
26-
case .managed:
27-
callback(.success(Response(awsRequestID: context.requestID, requestID: request.requestID, status: .error)))
28-
// trigger an "unmanaged" error - an unexpected Swift Error triggered while processing the request
29-
case .unmanaged(let error):
30-
callback(.failure(UnmanagedError(description: error)))
31-
// trigger a "fatal" error - a panic type error which will crash the process
32-
case .fatal:
33-
fatalError("crash!")
19+
@main
20+
struct ErrorsHappenHandler: AsyncLambdaHandler {
21+
typealias In = Request
22+
typealias Out = Response
23+
24+
init(context: Lambda.InitializationContext) async throws {}
25+
26+
func handle(event request: Request, context: Lambda.Context) async throws -> Response {
27+
// switch over the error type "requested" by the request, and trigger such error accordingly
28+
switch request.error {
29+
// no error here!
30+
case .none:
31+
return Response(awsRequestID: context.requestID, requestID: request.requestID, status: .ok)
32+
// trigger a "managed" error - domain specific business logic failure
33+
case .managed:
34+
return Response(awsRequestID: context.requestID, requestID: request.requestID, status: .error)
35+
// trigger an "unmanaged" error - an unexpected Swift Error triggered while processing the request
36+
case .unmanaged(let error):
37+
throw UnmanagedError(description: error)
38+
// trigger a "fatal" error - a panic type error which will crash the process
39+
case .fatal:
40+
fatalError("crash!")
41+
}
3442
}
3543
}
3644

Examples/LambdaFunctions/Sources/HelloWorld/main.swift renamed to Examples/LambdaFunctions/Sources/HelloWorld/HelloWorldHandler.swift

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@
1515
import AWSLambdaRuntime
1616

1717
// introductory example, the obligatory "hello, world!"
18-
Lambda.run { (_: Lambda.Context, _: String, callback: (Result<String, Error>) -> Void) in
19-
callback(.success("hello, world!"))
18+
@main
19+
struct HelloWorldHandler: AsyncLambdaHandler {
20+
typealias In = String
21+
typealias Out = String
22+
23+
init(context: Lambda.InitializationContext) async throws {
24+
// setup your resources that you want to reuse here.
25+
}
26+
27+
func handle(event: String, context: Lambda.Context) async throws -> String {
28+
"hello, world"
29+
}
2030
}

Examples/LocalDebugging/MyApp/MyApp.xcodeproj/project.pbxproj

+5-3
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
isa = PBXProject;
116116
attributes = {
117117
LastSwiftUpdateCheck = 1140;
118-
LastUpgradeCheck = 1140;
118+
LastUpgradeCheck = 1300;
119119
ORGANIZATIONNAME = "Tom Doron";
120120
TargetAttributes = {
121121
F7B6C1F9246121E800607A89 = {
@@ -205,6 +205,7 @@
205205
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
206206
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
207207
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
208+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
208209
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
209210
CLANG_WARN_STRICT_PROTOTYPES = YES;
210211
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -229,7 +230,7 @@
229230
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
230231
GCC_WARN_UNUSED_FUNCTION = YES;
231232
GCC_WARN_UNUSED_VARIABLE = YES;
232-
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
233+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
233234
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
234235
MTL_FAST_MATH = YES;
235236
ONLY_ACTIVE_ARCH = YES;
@@ -265,6 +266,7 @@
265266
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
266267
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
267268
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
269+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
268270
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
269271
CLANG_WARN_STRICT_PROTOTYPES = YES;
270272
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -283,7 +285,7 @@
283285
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
284286
GCC_WARN_UNUSED_FUNCTION = YES;
285287
GCC_WARN_UNUSED_VARIABLE = YES;
286-
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
288+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
287289
MTL_ENABLE_DEBUG_INFO = NO;
288290
MTL_FAST_MATH = YES;
289291
SDKROOT = iphoneos;

Examples/LocalDebugging/MyApp/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp.xcscheme

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1140"
3+
LastUpgradeVersion = "1300"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

Examples/LocalDebugging/MyApp/MyApp/ContentView.swift

+20-22
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ struct ContentView: View {
2525
TextField("Username", text: $name)
2626
SecureField("Password", text: $password)
2727
Button(
28-
action: self.register,
28+
action: {
29+
Task {
30+
await self.register()
31+
}
32+
},
2933
label: {
3034
Text("Register")
3135
.padding()
@@ -38,8 +42,8 @@ struct ContentView: View {
3842
}.padding(100)
3943
}
4044

41-
func register() {
42-
guard let url = URL(string: "http://localhost:7000/invoke") else {
45+
func register() async {
46+
guard let url = URL(string: "http://127.0.0.1:7000/invoke") else {
4347
fatalError("invalid url")
4448
}
4549
var request = URLRequest(url: url)
@@ -50,27 +54,21 @@ struct ContentView: View {
5054
}
5155
request.httpBody = jsonRequest
5256

53-
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
54-
do {
55-
if let error = error {
56-
throw CommunicationError(reason: error.localizedDescription)
57-
}
58-
guard let httpResponse = response as? HTTPURLResponse else {
59-
throw CommunicationError(reason: "invalid response, expected HTTPURLResponse")
60-
}
61-
guard httpResponse.statusCode == 200 else {
62-
throw CommunicationError(reason: "invalid response code: \(httpResponse.statusCode)")
63-
}
64-
guard let data = data else {
65-
throw CommunicationError(reason: "invald response, empty body")
66-
}
67-
let response = try JSONDecoder().decode(Response.self, from: data)
68-
self.setResponse(response.message)
69-
} catch {
70-
self.setResponse("\(error)")
57+
do {
58+
let (data, response) = try await URLSession.shared.data(for: request)
59+
60+
guard let httpResponse = response as? HTTPURLResponse else {
61+
throw CommunicationError(reason: "invalid response, expected HTTPURLResponse")
62+
}
63+
guard httpResponse.statusCode == 200 else {
64+
throw CommunicationError(reason: "invalid response code: \(httpResponse.statusCode)")
7165
}
66+
let jsonResponse = try JSONDecoder().decode(Response.self, from: data)
67+
68+
self.response = jsonResponse.message
69+
} catch {
70+
self.response = error.localizedDescription
7271
}
73-
task.resume()
7472
}
7573

7674
func setResponse(_ text: String) {

Examples/LocalDebugging/MyLambda/Package.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// swift-tools-version:5.2
1+
// swift-tools-version:5.5
22

33
import PackageDescription
44

55
let package = Package(
66
name: "MyLambda",
77
platforms: [
8-
.macOS(.v10_13),
8+
.macOS(.v12),
99
],
1010
products: [
1111
.executable(name: "MyLambda", targets: ["MyLambda"]),
@@ -18,7 +18,7 @@ let package = Package(
1818
.package(name: "Shared", path: "../Shared"),
1919
],
2020
targets: [
21-
.target(
21+
.executableTarget(
2222
name: "MyLambda", dependencies: [
2323
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
2424
.product(name: "Shared", package: "Shared"),

Examples/LocalDebugging/MyLambda/Sources/MyLambda/main.swift renamed to Examples/LocalDebugging/MyLambda/Sources/MyLambda/MyLambdaHandler.swift

+13-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ import Shared
1717

1818
// set LOCAL_LAMBDA_SERVER_ENABLED env variable to "true" to start
1919
// a local server simulator which will allow local debugging
20-
Lambda.run { (_, request: Request, callback: @escaping (Result<Response, Error>) -> Void) in
21-
// TODO: something useful
22-
callback(.success(Response(message: "Hello, \(request.name)!")))
20+
@main
21+
struct MyLambdaHandler: AsyncLambdaHandler {
22+
typealias In = Request
23+
typealias Out = Response
24+
25+
init(context: Lambda.InitializationContext) async throws {
26+
// setup your resources that you want to reuse for every invocation here.
27+
}
28+
29+
func handle(event request: Request, context: Lambda.Context) async throws -> Response {
30+
// TODO: something useful
31+
Response(message: "Hello, \(request.name)!")
32+
}
2333
}

0 commit comments

Comments
 (0)