Skip to content

Commit c22f527

Browse files
sebsto0xTim
andauthored
add HelloJSON example + README (#424)
* add HelloJSON example + README * multiple corrections of typos and grammatical errors Co-authored-by: Tim Condon <[email protected]>
1 parent 6b4e60d commit c22f527

File tree

10 files changed

+595
-345
lines changed

10 files changed

+595
-345
lines changed

.github/workflows/pull_request.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
# We pass the list of examples here, but we can't pass an array as argument
3636
# Instead, we pass a String with a valid JSON array.
3737
# The workaround is mentioned here https://github.com/orgs/community/discussions/11692
38-
examples: "[ 'HelloWorld', 'APIGateway','S3_AWSSDK', 'S3_Soto', 'Streaming', 'BackgroundTasks' ]"
38+
examples: "[ 'APIGateway', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'S3_AWSSDK', 'S3_Soto', 'Streaming' ]"
3939

4040
archive_plugin_enabled: true
4141

Examples/HelloJSON/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
response.json
2+
samconfig.toml
3+
template.yaml
4+
Makefile

Examples/HelloJSON/Package.swift

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// swift-tools-version:6.0
2+
3+
import PackageDescription
4+
5+
// needed for CI to test the local version of the library
6+
import struct Foundation.URL
7+
8+
#if os(macOS)
9+
let platforms: [PackageDescription.SupportedPlatform]? = [.macOS(.v15)]
10+
#else
11+
let platforms: [PackageDescription.SupportedPlatform]? = nil
12+
#endif
13+
14+
let package = Package(
15+
name: "swift-aws-lambda-runtime-example",
16+
platforms: platforms,
17+
products: [
18+
.executable(name: "HelloJSON", targets: ["HelloJSON"])
19+
],
20+
dependencies: [
21+
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
22+
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
23+
],
24+
targets: [
25+
.executableTarget(
26+
name: "HelloJSON",
27+
dependencies: [
28+
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
29+
]
30+
)
31+
]
32+
)
33+
34+
if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"],
35+
localDepsPath != "",
36+
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
37+
v.isDirectory == true
38+
{
39+
// when we use the local runtime as deps, let's remove the dependency added above
40+
let indexToRemove = package.dependencies.firstIndex { dependency in
41+
if case .sourceControl(
42+
name: _,
43+
location: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
44+
requirement: _
45+
) = dependency.kind {
46+
return true
47+
}
48+
return false
49+
}
50+
if let indexToRemove {
51+
package.dependencies.remove(at: indexToRemove)
52+
}
53+
54+
// then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..)
55+
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
56+
package.dependencies += [
57+
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
58+
]
59+
}

Examples/HelloJSON/README.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Hello JSON
2+
3+
This is a simple example of an AWS Lambda function that takes a JSON structure as an input parameter and returns a JSON structure as a response.
4+
5+
The runtime takes care of decoding the input and encoding the output.
6+
7+
## Code
8+
9+
The code defines `HelloRequest` and `HelloResponse` data structures to represent the input and output payloads. These structures are typically shared with a client project, such as an iOS application.
10+
11+
The code creates a `LambdaRuntime` struct. In it's simplest form, the initializer takes a function as an argument. The function is the handler that will be invoked when an event triggers the Lambda function.
12+
13+
The handler is `(event: HelloRequest, context: LambdaContext)`. The function takes two arguments:
14+
- the event argument is a `HelloRequest`. It is the parameter passed when invoking the function.
15+
- the context argument is a `Lambda Context`. It is a description of the runtime context.
16+
17+
The function return value will be encoded to a `HelloResponse` as your Lambda function response.
18+
19+
## Build & Package
20+
21+
To build & archive the package, type the following commands.
22+
23+
```bash
24+
swift package archive --allow-network-connections docker
25+
```
26+
27+
If there is no error, there is a ZIP file ready to deploy.
28+
The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HelloJSON/HelloJSON.zip`
29+
30+
## Deploy
31+
32+
Here is how to deploy using the `aws` command line.
33+
34+
```bash
35+
# Replace with your AWS Account ID
36+
AWS_ACCOUNT_ID=012345678901
37+
38+
aws lambda create-function \
39+
--function-name HelloJSON \
40+
--zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HelloJSON/HelloJSON.zip \
41+
--runtime provided.al2 \
42+
--handler provided \
43+
--architectures arm64 \
44+
--role arn:aws:iam::${AWS_ACCOUNT_ID}:role/lambda_basic_execution
45+
```
46+
47+
The `--architectures` flag is only required when you build the binary on an Apple Silicon machine (Apple M1 or more recent). It defaults to `x64`.
48+
49+
Be sure to define the `AWS_ACCOUNT_ID` environment variable with your actual AWS account ID (for example: 012345678901).
50+
51+
## Invoke your Lambda function
52+
53+
To invoke the Lambda function, use this `aws` command line.
54+
55+
```bash
56+
aws lambda invoke \
57+
--function-name HelloJSON \
58+
--payload $(echo '{ "name" : "Seb", "age" : 50 }' | base64) \
59+
out.txt && cat out.txt && rm out.txt
60+
```
61+
62+
Note that the payload is expected to be a valid JSON string.
63+
64+
This should output the following result.
65+
66+
```
67+
{
68+
"StatusCode": 200,
69+
"ExecutedVersion": "$LATEST"
70+
}
71+
{"greetings":"Hello Seb. You look younger than your age."}
72+
```
73+
74+
## Undeploy
75+
76+
When done testing, you can delete the Lambda function with this command.
77+
78+
```bash
79+
aws lambda delete-function --function-name HelloJSON
80+
```

Examples/HelloJSON/Sources/main.swift

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import AWSLambdaRuntime
16+
17+
// in this example we are receiving and responding with JSON structures
18+
19+
// the data structure to represent the input parameter
20+
struct HelloRequest: Decodable {
21+
let name: String
22+
let age: Int
23+
}
24+
25+
// the data structure to represent the output response
26+
struct HelloResponse: Encodable {
27+
let greetings: String
28+
}
29+
30+
// the Lambda runtime
31+
let runtime = LambdaRuntime {
32+
(event: HelloRequest, context: LambdaContext) in
33+
34+
HelloResponse(
35+
greetings: "Hello \(event.name). You look \(event.age > 30 ? "younger" : "older") than your age."
36+
)
37+
}
38+
39+
// start the loop
40+
try await runtime.run()

Examples/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ This directory contains example code for Lambda functions.
1818

1919
- **[BackgroundTasks](BackgroundTasks/README.md)**: a Lambda function that continues to run background tasks after having sent the response (requires [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)).
2020

21+
- **[HelloJSON](HelloJSON/README.md)**: a Lambda function that accepts JSON as an input parameter and responds with a JSON output (requires [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)).
22+
2123
- **[HelloWorld](HelloWorld/README.md)**: a simple Lambda function (requires [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)).
2224

2325
- **[S3_AWSSDK](S3_AWSSDK/README.md)**: a Lambda function that uses the [AWS SDK for Swift](https://docs.aws.amazon.com/sdk-for-swift/latest/developer-guide/getting-started.html) to invoke an [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) API (requires [AWS SAM](https://aws.amazon.com/serverless/sam/)).

Plugins/AWSLambdaPackager/Plugin.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ struct AWSLambdaPackager: CommandPlugin {
7474
"\(archives.count > 0 ? archives.count.description : "no") archive\(archives.count != 1 ? "s" : "") created"
7575
)
7676
for (product, archivePath) in archives {
77-
print(" * \(product.name) at \(archivePath)")
77+
print(" * \(product.name) at \(archivePath.path())")
7878
}
7979
}
8080

Plugins/AWSLambdaPackager/PluginUtils.swift

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ struct Utils {
2828
) throws -> String {
2929
if logLevel >= .debug {
3030
print("\(executable.path()) \(arguments.joined(separator: " "))")
31+
if let customWorkingDirectory {
32+
print("Working directory: \(customWorkingDirectory.path())")
33+
}
3134
}
3235

3336
let fd = dup(1)
@@ -85,8 +88,8 @@ struct Utils {
8588
process.standardError = pipe
8689
process.executableURL = executable
8790
process.arguments = arguments
88-
if let workingDirectory = customWorkingDirectory {
89-
process.currentDirectoryURL = URL(fileURLWithPath: workingDirectory.path())
91+
if let customWorkingDirectory {
92+
process.currentDirectoryURL = URL(fileURLWithPath: customWorkingDirectory.path())
9093
}
9194
process.terminationHandler = { _ in
9295
outputQueue.async {

0 commit comments

Comments
 (0)