Skip to content

Commit a5ff8e5

Browse files
authored
Add hummingbird Lambda example (#544)
Add Hummingbird web framework integration example for AWS Lambda **Motivation:** Developers using the Hummingbird web framework need a clear example of how to integrate it with AWS Lambda. The existing examples focus on basic Lambda handlers, but don't demonstrate how to use popular Swift web frameworks like Hummingbird in a serverless context. **Modifications:** Added a complete Hummingbird Lambda example in Examples/Hummingbird/ including Package.swift with Hummingbird Lambda dependencies, main.swift demonstrating router setup with API Gateway V2 integration, SAM template for deployment, and comprehensive README documentation with build, deploy, and usage instructions. **Result:** Developers can now easily create AWS Lambda functions using the Hummingbird web framework, with a working example that shows router configuration, API Gateway integration, and complete deployment workflow using familiar Hummingbird syntax.
1 parent 447c1e4 commit a5ff8e5

File tree

7 files changed

+209
-1
lines changed

7 files changed

+209
-1
lines changed

.github/workflows/pull_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
# We pass the list of examples here, but we can't pass an array as argument
3737
# Instead, we pass a String with a valid JSON array.
3838
# The workaround is mentioned here https://github.com/orgs/community/discussions/11692
39-
examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'StreamingFromEvent', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]"
39+
examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'HummingbirdLambda', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'StreamingFromEvent', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]"
4040
archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]"
4141
archive_plugin_enabled: true
4242

Examples/HummingbirdLambda/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc
9+
samconfig.toml
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// swift-tools-version: 6.1
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
// needed for CI to test the local version of the library
7+
import struct Foundation.URL
8+
9+
let package = Package(
10+
name: "HBLambda",
11+
platforms: [.macOS(.v15)],
12+
dependencies: [
13+
.package(
14+
url: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
15+
from: "2.0.0-beta.1"
16+
),
17+
.package(
18+
url: "https://github.com/hummingbird-project/hummingbird-lambda.git",
19+
branch: "main"
20+
),
21+
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.1.0"),
22+
],
23+
targets: [
24+
.executableTarget(
25+
name: "HBLambda",
26+
dependencies: [
27+
.product(name: "HummingbirdLambda", package: "hummingbird-lambda"),
28+
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
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/HummingbirdLambda/README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Hummingbird Lambda
2+
3+
This is a simple example of an AWS Lambda function using the [Hummingbird](https://github.com/hummingbird-project/hummingbird) web framework, invoked through an Amazon API Gateway.
4+
5+
## Code
6+
7+
The Lambda function uses Hummingbird's router to handle HTTP requests. It defines a simple GET endpoint at `/hello` that returns "Hello".
8+
9+
The code creates a `Router` with `AppRequestContext` (which is a type alias for `BasicLambdaRequestContext<APIGatewayV2Request>`). The router defines HTTP routes using Hummingbird's familiar syntax.
10+
11+
The `APIGatewayV2LambdaFunction` wraps the Hummingbird router to make it compatible with AWS Lambda and API Gateway V2 events.
12+
13+
`APIGatewayV2Request` is defined in the [Swift AWS Lambda Events](https://github.com/swift-server/swift-aws-lambda-events) library, and the Hummingbird Lambda integration is provided by the [Hummingbird Lambda](https://github.com/hummingbird-project/hummingbird-lambda) package.
14+
15+
## Build & Package
16+
17+
To build the package, type the following commands.
18+
19+
```bash
20+
swift build
21+
swift package archive --allow-network-connections docker
22+
```
23+
24+
If there is no error, there is a ZIP file ready to deploy.
25+
The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HBLambda/HBLambda.zip`
26+
27+
## Deploy
28+
29+
The deployment must include the Lambda function and the API Gateway. We use the [Serverless Application Model (SAM)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) to deploy the infrastructure.
30+
31+
**Prerequisites** : Install the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)
32+
33+
The example directory contains a file named `template.yaml` that describes the deployment.
34+
35+
To actually deploy your Lambda function and create the infrastructure, type the following `sam` command.
36+
37+
```bash
38+
sam deploy \
39+
--resolve-s3 \
40+
--template-file template.yaml \
41+
--stack-name HummingbirdLambda \
42+
--capabilities CAPABILITY_IAM
43+
```
44+
45+
At the end of the deployment, the script lists the API Gateway endpoint.
46+
The output is similar to this one.
47+
48+
```
49+
-----------------------------------------------------------------------------------------------------------------------------
50+
Outputs
51+
-----------------------------------------------------------------------------------------------------------------------------
52+
Key APIGatewayEndpoint
53+
Description API Gateway endpoint URL"
54+
Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com
55+
-----------------------------------------------------------------------------------------------------------------------------
56+
```
57+
58+
## Invoke your Lambda function
59+
60+
To invoke the Lambda function, use this `curl` command line to call the `/hello` endpoint.
61+
62+
```bash
63+
curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com/hello
64+
```
65+
66+
Be sure to replace the URL with the API Gateway endpoint returned in the previous step.
67+
68+
This should print:
69+
70+
```bash
71+
Hello
72+
```
73+
74+
## Undeploy
75+
76+
When done testing, you can delete the infrastructure with this command.
77+
78+
```bash
79+
sam delete
80+
```
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 AWSLambdaEvents
16+
import HummingbirdLambda
17+
import Logging
18+
19+
typealias AppRequestContext = BasicLambdaRequestContext<APIGatewayV2Request>
20+
let router = Router(context: AppRequestContext.self)
21+
22+
router.get("hello") { _, _ in
23+
"Hello"
24+
}
25+
26+
let lambda = APIGatewayV2LambdaFunction(router: router)
27+
try await lambda.runService()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: SAM Template for Hummingbird Lambda Example
4+
5+
Resources:
6+
# Lambda function
7+
HBLambda:
8+
Type: AWS::Serverless::Function
9+
Properties:
10+
CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HBLambda/HBLambda.zip
11+
Timeout: 60
12+
Handler: swift.bootstrap # ignored by the Swift runtime
13+
Runtime: provided.al2
14+
MemorySize: 512
15+
Architectures:
16+
- arm64
17+
Environment:
18+
Variables:
19+
# by default, AWS Lambda runtime produces no log
20+
# use `LOG_LEVEL: debug` for for lifecycle and event handling information
21+
# use `LOG_LEVEL: trace` for detailed input event information
22+
LOG_LEVEL: debug
23+
Events:
24+
HttpApiEvent:
25+
Type: HttpApi
26+
27+
Outputs:
28+
# print API Gateway endpoint
29+
APIGatewayEndpoint:
30+
Description: API Gateway endpoint URI"
31+
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"

Examples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ This directory contains example code for Lambda functions.
2828

2929
- **[HelloWorld](HelloWorld/README.md)**: a simple Lambda function (requires [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)).
3030

31+
- **[Hummingbird](Hummingbird/README.md)**: a Lambda function using the Hummingbird web framework with API Gateway integration (requires [AWS SAM](https://aws.amazon.com/serverless/sam/)).
32+
3133
- **[S3EventNotifier](S3EventNotifier/README.md)**: a Lambda function that receives object-upload notifications from an [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) bucket.
3234

3335
- **[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/)).

0 commit comments

Comments
 (0)