Skip to content

Commit 419f054

Browse files
authored
Lambda basics scenario example for Swift (#7182)
* Full scenario example for Lambda in Swift This PR includes a complete implementation of the "basics" scenario example for the AWS SDK for Swift.
1 parent 3441397 commit 419f054

File tree

10 files changed

+1100
-0
lines changed

10 files changed

+1100
-0
lines changed

.doc_gen/metadata/lambda_metadata.yaml

+63
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ lambda_CreateFunction:
172172
- snippet_tags:
173173
- lambda.rust.scenario.create_function
174174
- lambda.rust.scenario.prepare_function
175+
Swift:
176+
versions:
177+
- sdk_version: 1
178+
github: swift/example_code/lambda/basics
179+
excerpts:
180+
- description:
181+
snippet_tags:
182+
- swift.lambda-basics.imports
183+
- swift.lambda-basics.CreateFunction
175184
services:
176185
lambda: {CreateFunction}
177186
lambda_DeleteFunction:
@@ -380,6 +389,15 @@ lambda_Invoke:
380389
- snippet_tags:
381390
- lambda.rust.scenario.invoke
382391
- lambda.rust.scenario.log_invoke_output
392+
Swift:
393+
versions:
394+
- sdk_version: 1
395+
github: swift/example_code/lambda/basics
396+
excerpts:
397+
- description:
398+
snippet_tags:
399+
- swift.lambda-basics.imports
400+
- swift.lambda-basics.Invoke
383401
services:
384402
lambda: {Invoke}
385403
lambda_GetFunction:
@@ -474,6 +492,15 @@ lambda_GetFunction:
474492
excerpts:
475493
- snippet_tags:
476494
- lambda.rust.scenario.get_function
495+
Swift:
496+
versions:
497+
- sdk_version: 1
498+
github: swift/example_code/lambda/basics
499+
excerpts:
500+
- description:
501+
snippet_tags:
502+
- swift.lambda-basics.imports
503+
- swift.lambda-basics.GetFunctionInput
477504
services:
478505
lambda: {GetFunction}
479506
lambda_UpdateFunctionCode:
@@ -569,6 +596,15 @@ lambda_UpdateFunctionCode:
569596
- snippet_tags:
570597
- lambda.rust.scenario.update_function_code
571598
- lambda.rust.scenario.prepare_function
599+
Swift:
600+
versions:
601+
- sdk_version: 1
602+
github: swift/example_code/lambda/basics
603+
excerpts:
604+
- description:
605+
snippet_tags:
606+
- swift.lambda-basics.imports
607+
- swift.lambda-basics.UpdateFunctionCode
572608
services:
573609
lambda: {UpdateFunctionCode}
574610
lambda_UpdateFunctionConfiguration:
@@ -748,6 +784,15 @@ lambda_ListFunctions:
748784
excerpts:
749785
- snippet_tags:
750786
- lambda.rust.scenario.list_functions
787+
Swift:
788+
versions:
789+
- sdk_version: 1
790+
github: swift/example_code/lambda/basics
791+
excerpts:
792+
- description:
793+
snippet_tags:
794+
- swift.lambda-basics.imports
795+
- swift.lambda-basics.ListFunctionsPaginated
751796
services:
752797
lambda: {ListFunctions}
753798
lambda_Scenario_GettingStartedFunctions:
@@ -937,5 +982,23 @@ lambda_Scenario_GettingStartedFunctions:
937982
This file is src/bin/scenario.rs in the crate.
938983
snippet_files:
939984
- rustv1/examples/lambda/src/bin/scenario.rs
985+
Swift:
986+
versions:
987+
- sdk_version: 1
988+
github: swift/example_code/lambda/basics
989+
excerpts:
990+
- description: Define the first &LAM; function, which simply increments the specified value.
991+
snippet_files:
992+
- swift/example_code/lambda/basics/increment/Package.swift
993+
- swift/example_code/lambda/basics/increment/Sources/increment.swift
994+
- description: Define the second &LAM; function, which performs an arithmetic operation on two numbers.
995+
snippet_files:
996+
- swift/example_code/lambda/basics/calculator/Package.swift
997+
- swift/example_code/lambda/basics/calculator/Sources/calculator.swift
998+
- description: Define the main program that will invoke the two &LAM; functions.
999+
snippet_files:
1000+
- swift/example_code/lambda/basics/lambda-basics/Package.swift
1001+
- swift/example_code/lambda/basics/lambda-basics/Sources/entry.swift
1002+
- swift/example_code/lambda/basics/lambda-basics/Sources/ExampleError.swift
9401003
services:
9411004
lambda: {CreateFunction, DeleteFunction, Invoke, GetFunction, ListFunctions, UpdateFunctionCode, UpdateFunctionConfiguration}

swift/example_code/lambda/README.md

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Lambda code examples for the SDK for Swift
2+
3+
## Overview
4+
5+
Shows how to use the AWS SDK for Swift to work with AWS Lambda.
6+
7+
<!--custom.overview.start-->
8+
<!--custom.overview.end-->
9+
10+
_Lambda allows you to run code without provisioning or managing servers._
11+
12+
## ⚠ Important
13+
14+
* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/).
15+
* Running the tests might result in charges to your AWS account.
16+
* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
17+
* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).
18+
19+
<!--custom.important.start-->
20+
<!--custom.important.end-->
21+
22+
## Code examples
23+
24+
### Prerequisites
25+
26+
For prerequisites, see the [README](../../README.md#Prerequisites) in the `swift` folder.
27+
28+
29+
<!--custom.prerequisites.start-->
30+
<!--custom.prerequisites.end-->
31+
32+
### Basics
33+
34+
Code examples that show you how to perform the essential operations within a service.
35+
36+
- [Learn the basics](basics/increment/Package.swift)
37+
38+
39+
### Single actions
40+
41+
Code excerpts that show you how to call individual service functions.
42+
43+
- [CreateFunction](basics/lambda-basics/Sources/entry.swift#L177)
44+
- [GetFunction](basics/lambda-basics/Sources/entry.swift#L142)
45+
- [Invoke](basics/lambda-basics/Sources/entry.swift#L313)
46+
- [ListFunctions](basics/lambda-basics/Sources/entry.swift#L283)
47+
- [UpdateFunctionCode](basics/lambda-basics/Sources/entry.swift#L236)
48+
49+
50+
<!--custom.examples.start-->
51+
<!--custom.examples.end-->
52+
53+
## Run the examples
54+
55+
### Instructions
56+
57+
To build any of these examples from a terminal window, navigate into its
58+
directory, then use the following command:
59+
60+
```
61+
$ swift build
62+
```
63+
64+
To build one of these examples in Xcode, navigate to the example's directory
65+
(such as the `ListUsers` directory, to build that example). Then type `xed.`
66+
to open the example directory in Xcode. You can then use standard Xcode build
67+
and run commands.
68+
69+
<!--custom.instructions.start-->
70+
<!--custom.instructions.end-->
71+
72+
73+
#### Learn the basics
74+
75+
This example shows you how to do the following:
76+
77+
- Create an IAM role and Lambda function, then upload handler code.
78+
- Invoke the function with a single parameter and get results.
79+
- Update the function code and configure with an environment variable.
80+
- Invoke the function with new parameters and get results. Display the returned execution log.
81+
- List the functions for your account, then clean up resources.
82+
83+
<!--custom.basic_prereqs.lambda_Scenario_GettingStartedFunctions.start-->
84+
<!--custom.basic_prereqs.lambda_Scenario_GettingStartedFunctions.end-->
85+
86+
87+
<!--custom.basics.lambda_Scenario_GettingStartedFunctions.start-->
88+
##### Build and deploy the example
89+
90+
This example consists of the main program and two AWS Lambda functions. To
91+
build and deploy it:
92+
93+
1. Build the `increment` lambda function (`cd increment && swift build`).
94+
2. Archive the `increment` lambda function for use as a Lambda function:
95+
`swift package archive --allow-network-connections docker`. When archiving
96+
is complete, the archive's path is displayed. Take note of it.
97+
3. Build the `calculator` lambda function (`cd ../calculator && swift build`).
98+
4. Archive it for use as a Lambda function: `swift package archive
99+
--allow-network-connections docker`. Take note of this created Zip file's
100+
path, too.
101+
5. Build the main program in the `lambda-basics` directory.
102+
6. Run the main program with the command `swift run lambda-basics --incpath <path-of-increment-archive> --calcpath <path-of-calculator-archive>`.
103+
<!--custom.basics.lambda_Scenario_GettingStartedFunctions.end-->
104+
105+
106+
### Tests
107+
108+
⚠ Running tests might result in charges to your AWS account.
109+
110+
111+
To find instructions for running these tests, see the [README](../../README.md#Tests)
112+
in the `swift` folder.
113+
114+
115+
116+
<!--custom.tests.start-->
117+
<!--custom.tests.end-->
118+
119+
## Additional resources
120+
121+
- [Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)
122+
- [Lambda API Reference](https://docs.aws.amazon.com/lambda/latest/dg/API_Reference.html)
123+
- [SDK for Swift Lambda reference](https://sdk.amazonaws.com/swift/api/awslambda/latest/documentation/awslambda)
124+
125+
<!--custom.resources.start-->
126+
<!--custom.resources.end-->
127+
128+
---
129+
130+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
131+
132+
SPDX-License-Identifier: Apache-2.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// swift-tools-version: 5.9
2+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// The swift-tools-version declares the minimum version of Swift required to
6+
// build this package.
7+
8+
import PackageDescription
9+
10+
let package = Package(
11+
name: "calculator",
12+
// Let Xcode know the minimum Apple platforms supported.
13+
platforms: [
14+
.macOS(.v13)
15+
],
16+
dependencies: [
17+
// Dependencies declare other packages that this package depends on.
18+
.package(
19+
url: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
20+
from: "1.0.0-alpha"),
21+
],
22+
targets: [
23+
// Targets are the basic building blocks of a package, defining a module or a test suite.
24+
// Targets can depend on other targets in this package and products
25+
// from dependencies.
26+
.executableTarget(
27+
name: "calculator",
28+
dependencies: [
29+
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
30+
],
31+
path: "Sources"
32+
)
33+
]
34+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
// snippet-start:[lambda.swift.calculator.complete]
4+
// snippet-start:[lambda.swift.calculator.imports]
5+
import Foundation
6+
import AWSLambdaRuntime
7+
// snippet-end:[lambda.swift.calculator.imports]
8+
9+
// snippet-start:[lambda.swift.calculator.types]
10+
// snippet-start:[lambda.swift.calculator.struct.request]
11+
/// Represents the contents of the requests being received from the client.
12+
/// This structure must be `Decodable` to indicate that its initializer
13+
/// converts an external representation into this type.
14+
struct Request: Decodable, Sendable {
15+
/// The action to perform.
16+
let action: String
17+
/// The first number to act upon.
18+
let x: Int
19+
/// The second number to act upon.
20+
let y: Int
21+
}
22+
// snippet-end:[lambda.swift.calculator.struct.request]
23+
24+
// snippet-start:[lambda.swift.calculator.actions]
25+
/// A dictionary mapping operation names to closures that perform that
26+
/// operation and return the result.
27+
let actions = [
28+
"plus": { (x: Int, y: Int) -> Int in
29+
return x + y
30+
},
31+
"minus": { (x: Int, y: Int) -> Int in
32+
return x - y
33+
},
34+
"times": { (x: Int, y: Int) -> Int in
35+
return x * y
36+
},
37+
"divided-by": { (x: Int, y: Int) -> Int in
38+
return x / y
39+
}
40+
]
41+
// snippet-end:[lambda.swift.calculator.actions]
42+
43+
// snippet-start:[lambda.swift.calculator.struct.response]
44+
/// The contents of the response sent back to the client. This must be
45+
/// `Encodable`.
46+
struct Response: Encodable, Sendable {
47+
/// The resulting value after performing the action.
48+
let answer: Int?
49+
}
50+
// snippet-end:[lambda.swift.calculator.struct.response]
51+
52+
// snippet-end:[lambda.swift.calculator.types]
53+
54+
// snippet-start:[lambda.swift.calculator.handler]
55+
/// A Swift AWS Lambda Runtime `LambdaHandler` lets you both perform needed
56+
/// initialization and handle AWS Lambda requests. There are other handler
57+
/// protocols available for other use cases.
58+
@main
59+
struct CalculatorLambda: LambdaHandler {
60+
61+
// snippet-start:[lambda.swift.calculator.handler.init]
62+
/// Initialize the AWS Lambda runtime.
63+
///
64+
/// ^ The logger is a standard Swift logger. You can control the verbosity
65+
/// by setting the `LOG_LEVEL` environment variable.
66+
init(context: LambdaInitializationContext) async throws {
67+
// Display the `LOG_LEVEL` configuration for this process.
68+
context.logger.info(
69+
"Log Level env var : \(ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "info" )"
70+
)
71+
}
72+
// snippet-end:[lambda.swift.calculator.handler.init]
73+
74+
// snippet-start:[lambda.swift.calculator.handler.handle]
75+
/// The Lambda function's entry point. Called by the Lambda runtime.
76+
///
77+
/// - Parameters:
78+
/// - event: The `Request` describing the request made by the
79+
/// client.
80+
/// - context: A `LambdaContext` describing the context in
81+
/// which the lambda function is running.
82+
///
83+
/// - Returns: A `Response` object that will be encoded to JSON and sent
84+
/// to the client by the Lambda runtime.
85+
func handle(_ event: Request, context: LambdaContext) async throws -> Response {
86+
let action = event.action
87+
var answer: Int?
88+
var actionFunc: ((Int, Int) -> Int)?
89+
90+
// Get the closure to run to perform the calculation.
91+
92+
actionFunc = actions[action]
93+
94+
guard let actionFunc else {
95+
context.logger.error("Unrecognized operation '\(action)\'")
96+
return Response(answer: nil)
97+
}
98+
99+
// Perform the calculation and return the answer.
100+
101+
answer = actionFunc(event.x, event.y)
102+
103+
guard let answer else {
104+
context.logger.error("Error computing \(event.x) \(action) \(event.y)")
105+
}
106+
context.logger.info("\(event.x) \(action) \(event.y) = \(answer)")
107+
108+
return Response(answer: answer)
109+
}
110+
// snippet-end:[lambda.swift.calculator.handler.handle]
111+
}
112+
// snippet-end:[lambda.swift.calculator.handler]
113+
// snippet-end:[lambda.swift.calculator.complete]

0 commit comments

Comments
 (0)