Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
# We pass the list of examples here, but we can't pass an array as argument
# Instead, we pass a String with a valid JSON array.
# The workaround is mentioned here https://github.com/orgs/community/discussions/11692
examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'Testing', 'Tutorial' ]"
examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'StreamingFromEvent', 'Testing', 'Tutorial' ]"
archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]"
archive_plugin_enabled: true

Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ Package.resolved
.vscode
Makefile
.devcontainer
.amazonq
.amazonq
samconfig.toml
4 changes: 3 additions & 1 deletion Examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ This directory contains example code for Lambda functions.

- **[S3_Soto](S3_Soto/README.md)**: a Lambda function that uses [Soto](https://github.com/soto-project/soto) 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/)).

- **[Streaming]**: create a Lambda function exposed as an URL. The Lambda function streams its response over time. (requires [AWS SAM](https://aws.amazon.com/serverless/sam/)).
- **[Streaming](Streaming/README.md)**: create a Lambda function exposed as an URL. The Lambda function streams its response over time. (requires [AWS SAM](https://aws.amazon.com/serverless/sam/)).

- **[StreamingFromEvent](StreamingFromEvent/README.md)**: a Lambda function that combines JSON input decoding with response streaming capabilities, demonstrating the new streaming codable interface (requires [AWS SAM](https://aws.amazon.com/serverless/sam/) or the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)).

- **[Testing](Testing/README.md)**: a test suite for Lambda functions.

Expand Down
66 changes: 66 additions & 0 deletions Examples/Streaming/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,69 @@ When done testing, you can delete the infrastructure with this command.
```bash
sam delete
```

## Payload decoding

The content of the input `ByteBuffer` depends on how you invoke the function:

- when you use [`InvokeWithResponseStream` API](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) to invoke the function, the function incoming payload is what you pass to the API. You can decode the `ByteBuffer` with a [`JSONDecoder.decode()`](https://developer.apple.com/documentation/foundation/jsondecoder) function call.
- when you invoke the function through a [Lambda function URL](https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html), the incoming `ByteBuffer` contains a payload that gives developer access to the underlying HTTP call. The payload contains information about the HTTP verb used, the headers received, the authentication method and so on. The [AWS documentation contains the details](https://docs.aws.amazon.com/lambda/latest/dg/urls-invocation.html) of the payload. The [Swift Lambda Event library](https://github.com/swift-server/swift-aws-lambda-events) contains a [`FunctionURL` type](https://github.com/swift-server/swift-aws-lambda-events/blob/main/Sources/AWSLambdaEvents/FunctionURL.swift) ready to use in your projects.

Here is an example of Lambda function URL payload:

```json
// This is an example of payload received when
// the function is invoked by a Lambda function URL.
// You can use the `FunctionURL` structure provided by the Lambda Event library to decode this
// See, https://github.com/swift-server/swift-aws-lambda-events/blob/main/Sources/AWSLambdaEvents/FunctionURL.swift

/*
{
"version": "2.0",
"routeKey": "$default",
"rawPath": "/",
"rawQueryString": "",
"headers": {
"x-amzn-tls-cipher-suite": "TLS_AES_128_GCM_SHA256",
"x-amzn-tls-version": "TLSv1.3",
"x-amzn-trace-id": "Root=1-68762f44-4f6a87d1639e7fc356aa6f96",
"x-amz-date": "20250715T103651Z",
"x-forwarded-proto": "https",
"host": "zvnsvhpx7u5gn3l3euimg4jjou0jvbfe.lambda-url.us-east-1.on.aws",
"x-forwarded-port": "443",
"x-forwarded-for": "2a01:cb0c:6de:8300:a1be:8004:e31a:b9f",
"accept": "*/*",
"user-agent": "curl/8.7.1"
},
"requestContext": {
"accountId": "0123456789",
"apiId": "zvnsvhpx7u5gn3l3euimg4jjou0jvbfe",
"authorizer": {
"iam": {
"accessKey": "AKIA....",
"accountId": "0123456789",
"callerId": "AIDA...",
"cognitoIdentity": null,
"principalOrgId": "o-rlrup7z3ao",
"userArn": "arn:aws:iam::0123456789:user/sst",
"userId": "AIDA..."
}
},
"domainName": "zvnsvhpx7u5gn3l3euimg4jjou0jvbfe.lambda-url.us-east-1.on.aws",
"domainPrefix": "zvnsvhpx7u5gn3l3euimg4jjou0jvbfe",
"http": {
"method": "GET",
"path": "/",
"protocol": "HTTP/1.1",
"sourceIp": "2a01:...:b9f",
"userAgent": "curl/8.7.1"
},
"requestId": "f942509a-283f-4c4f-94f8-0d4ccc4a00f8",
"routeKey": "$default",
"stage": "$default",
"time": "15/Jul/2025:10:36:52 +0000",
"timeEpoch": 1752575812081
},
"isBase64Encoded": false
}
```
50 changes: 50 additions & 0 deletions Examples/StreamingFromEvent/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// swift-tools-version: 6.0

import PackageDescription

// needed for CI to test the local version of the library
import struct Foundation.URL

let package = Package(
name: "StreamingFromEvent",
platforms: [.macOS(.v15)],
dependencies: [
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
],
targets: [
.executableTarget(
name: "StreamingFromEvent",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
]
)
]
)

if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something for a potential future PR - it would be good to simplify these example manifest and remove all of this in favour of a swift package edit in CI

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, tracked here #536
However we should also consider development of the library itself and the examples. It's convenient to build with AS_LAMBDA_LOCAL_DEPS=../..

localDepsPath != "",
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
v.isDirectory == true
{
// when we use the local runtime as deps, let's remove the dependency added above
let indexToRemove = package.dependencies.firstIndex { dependency in
if case .sourceControl(
name: _,
location: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
requirement: _
) = dependency.kind {
return true
}
return false
}
if let indexToRemove {
package.dependencies.remove(at: indexToRemove)
}

// then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..)
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
package.dependencies += [
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
]
}
Loading