From 481037bf125a1c96fbd41b1a8f405b528054f720 Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Sun, 3 Aug 2025 16:28:43 +0200 Subject: [PATCH 1/6] add hummingbirdLambda example --- Examples/Humingbird/.gitignore | 9 +++ Examples/Humingbird/Package.swift | 59 +++++++++++++++++++ Examples/Humingbird/README.md | 80 ++++++++++++++++++++++++++ Examples/Humingbird/Sources/main.swift | 13 +++++ Examples/Humingbird/template.yaml | 31 ++++++++++ 5 files changed, 192 insertions(+) create mode 100644 Examples/Humingbird/.gitignore create mode 100644 Examples/Humingbird/Package.swift create mode 100644 Examples/Humingbird/README.md create mode 100644 Examples/Humingbird/Sources/main.swift create mode 100644 Examples/Humingbird/template.yaml diff --git a/Examples/Humingbird/.gitignore b/Examples/Humingbird/.gitignore new file mode 100644 index 00000000..fe6e212a --- /dev/null +++ b/Examples/Humingbird/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +samconfig.toml \ No newline at end of file diff --git a/Examples/Humingbird/Package.swift b/Examples/Humingbird/Package.swift new file mode 100644 index 00000000..58a6c877 --- /dev/null +++ b/Examples/Humingbird/Package.swift @@ -0,0 +1,59 @@ +// swift-tools-version: 6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +// needed for CI to test the local version of the library +import struct Foundation.URL + +let package = Package( + name: "HBLambda", + platforms: [.macOS(.v15)], + dependencies: [ + .package( + url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", + from: "2.0.0-beta.1" + ), + .package( + url: "https://github.com/hummingbird-project/hummingbird-lambda.git", + branch: "main" + ), + .package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.1.0"), + ], + targets: [ + .executableTarget( + name: "HBLambda", + dependencies: [ + .product(name: "HummingbirdLambda", package: "hummingbird-lambda"), + .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), + ] + ) + ] +) + +if let localDepsPath = Context.environment["LAMBDA_USE_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) + ] +} diff --git a/Examples/Humingbird/README.md b/Examples/Humingbird/README.md new file mode 100644 index 00000000..11e2bf0f --- /dev/null +++ b/Examples/Humingbird/README.md @@ -0,0 +1,80 @@ +# Hummingbird Lambda + +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. + +## Code + +The Lambda function uses Hummingbird's router to handle HTTP requests. It defines a simple GET endpoint at `/hello` that returns "Hello". + +The code creates a `Router` with `AppRequestContext` (which is a type alias for `BasicLambdaRequestContext`). The router defines HTTP routes using Hummingbird's familiar syntax. + +The `APIGatewayV2LambdaFunction` wraps the Hummingbird router to make it compatible with AWS Lambda and API Gateway V2 events. + +`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. + +## Build & Package + +To build the package, type the following commands. + +```bash +swift build +swift package archive --allow-network-connections docker +``` + +If there is no error, there is a ZIP file ready to deploy. +The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HBLambda/HBLambda.zip` + +## Deploy + +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. + +**Prerequisites** : Install the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) + +The example directory contains a file named `template.yaml` that describes the deployment. + +To actually deploy your Lambda function and create the infrastructure, type the following `sam` command. + +```bash +sam deploy \ +--resolve-s3 \ +--template-file template.yaml \ +--stack-name HummingbirdLambda \ +--capabilities CAPABILITY_IAM +``` + +At the end of the deployment, the script lists the API Gateway endpoint. +The output is similar to this one. + +``` +----------------------------------------------------------------------------------------------------------------------------- +Outputs +----------------------------------------------------------------------------------------------------------------------------- +Key APIGatewayEndpoint +Description API Gateway endpoint URL" +Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com +----------------------------------------------------------------------------------------------------------------------------- +``` + +## Invoke your Lambda function + +To invoke the Lambda function, use this `curl` command line to call the `/hello` endpoint. + +```bash +curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com/hello +``` + +Be sure to replace the URL with the API Gateway endpoint returned in the previous step. + +This should print: + +```bash +Hello +``` + +## Undeploy + +When done testing, you can delete the infrastructure with this command. + +```bash +sam delete +``` \ No newline at end of file diff --git a/Examples/Humingbird/Sources/main.swift b/Examples/Humingbird/Sources/main.swift new file mode 100644 index 00000000..e78e2d2a --- /dev/null +++ b/Examples/Humingbird/Sources/main.swift @@ -0,0 +1,13 @@ +import AWSLambdaEvents +import HummingbirdLambda +import Logging + +typealias AppRequestContext = BasicLambdaRequestContext +let router = Router(context: AppRequestContext.self) + +router.get("hello") { _, _ in + "Hello" +} + +let lambda = APIGatewayV2LambdaFunction(router: router) +try await lambda.runService() diff --git a/Examples/Humingbird/template.yaml b/Examples/Humingbird/template.yaml new file mode 100644 index 00000000..7bf9a272 --- /dev/null +++ b/Examples/Humingbird/template.yaml @@ -0,0 +1,31 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: SAM Template for Hummingbird Lambda Example + +Resources: + # Lambda function + HBLambda: + Type: AWS::Serverless::Function + Properties: + CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HBLambda/HBLambda.zip + Timeout: 60 + Handler: swift.bootstrap # ignored by the Swift runtime + Runtime: provided.al2 + MemorySize: 512 + Architectures: + - arm64 + Environment: + Variables: + # by default, AWS Lambda runtime produces no log + # use `LOG_LEVEL: debug` for for lifecycle and event handling information + # use `LOG_LEVEL: trace` for detailed input event information + LOG_LEVEL: debug + Events: + HttpApiEvent: + Type: HttpApi + +Outputs: + # print API Gateway endpoint + APIGatewayEndpoint: + Description: API Gateway endpoint URI" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" From 58bae4ab94700c8f459c0c37e0a15a8d057171eb Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Sun, 3 Aug 2025 16:33:01 +0200 Subject: [PATCH 2/6] add HBLambda to the list of examples --- Examples/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Examples/README.md b/Examples/README.md index 76156d6e..2f3fa92f 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -28,6 +28,8 @@ This directory contains example code for Lambda functions. - **[HelloWorld](HelloWorld/README.md)**: a simple Lambda function (requires [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)). +- **[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/)). + - **[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. - **[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/)). From 5e2490bde1374483edef606923b348f0a79a75fe Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Sun, 3 Aug 2025 16:33:09 +0200 Subject: [PATCH 3/6] add license header --- Examples/Humingbird/Sources/main.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Examples/Humingbird/Sources/main.swift b/Examples/Humingbird/Sources/main.swift index e78e2d2a..15d19099 100644 --- a/Examples/Humingbird/Sources/main.swift +++ b/Examples/Humingbird/Sources/main.swift @@ -1,3 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + import AWSLambdaEvents import HummingbirdLambda import Logging From aa87320e11ecf614b65d72850e0b7a250daca6fd Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Sun, 3 Aug 2025 16:34:26 +0200 Subject: [PATCH 4/6] [CI] add hblambda to the list of examples --- .github/workflows/pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 3364da01..b0ba8c0f 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -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', 'StreamingFromEvent', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]" + examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'Hummingbird', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'StreamingFromEvent', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]" archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]" archive_plugin_enabled: true From 1ec9048346c4148d073bccbec863071694873a4f Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Sun, 3 Aug 2025 16:34:34 +0200 Subject: [PATCH 5/6] fix typo --- Examples/{Humingbird => Hummingbird}/.gitignore | 0 Examples/{Humingbird => Hummingbird}/Package.swift | 0 Examples/{Humingbird => Hummingbird}/README.md | 0 Examples/{Humingbird => Hummingbird}/Sources/main.swift | 0 Examples/{Humingbird => Hummingbird}/template.yaml | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename Examples/{Humingbird => Hummingbird}/.gitignore (100%) rename Examples/{Humingbird => Hummingbird}/Package.swift (100%) rename Examples/{Humingbird => Hummingbird}/README.md (100%) rename Examples/{Humingbird => Hummingbird}/Sources/main.swift (100%) rename Examples/{Humingbird => Hummingbird}/template.yaml (100%) diff --git a/Examples/Humingbird/.gitignore b/Examples/Hummingbird/.gitignore similarity index 100% rename from Examples/Humingbird/.gitignore rename to Examples/Hummingbird/.gitignore diff --git a/Examples/Humingbird/Package.swift b/Examples/Hummingbird/Package.swift similarity index 100% rename from Examples/Humingbird/Package.swift rename to Examples/Hummingbird/Package.swift diff --git a/Examples/Humingbird/README.md b/Examples/Hummingbird/README.md similarity index 100% rename from Examples/Humingbird/README.md rename to Examples/Hummingbird/README.md diff --git a/Examples/Humingbird/Sources/main.swift b/Examples/Hummingbird/Sources/main.swift similarity index 100% rename from Examples/Humingbird/Sources/main.swift rename to Examples/Hummingbird/Sources/main.swift diff --git a/Examples/Humingbird/template.yaml b/Examples/Hummingbird/template.yaml similarity index 100% rename from Examples/Humingbird/template.yaml rename to Examples/Hummingbird/template.yaml From 3e9a969abe6e76fd8e799d346ef9c7186c10ea3d Mon Sep 17 00:00:00 2001 From: Sebastien Stormacq Date: Sun, 3 Aug 2025 16:51:36 +0200 Subject: [PATCH 6/6] rename directory --- .github/workflows/pull_request.yml | 2 +- Examples/{Hummingbird => HummingbirdLambda}/.gitignore | 0 Examples/{Hummingbird => HummingbirdLambda}/Package.swift | 0 Examples/{Hummingbird => HummingbirdLambda}/README.md | 0 Examples/{Hummingbird => HummingbirdLambda}/Sources/main.swift | 0 Examples/{Hummingbird => HummingbirdLambda}/template.yaml | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename Examples/{Hummingbird => HummingbirdLambda}/.gitignore (100%) rename Examples/{Hummingbird => HummingbirdLambda}/Package.swift (100%) rename Examples/{Hummingbird => HummingbirdLambda}/README.md (100%) rename Examples/{Hummingbird => HummingbirdLambda}/Sources/main.swift (100%) rename Examples/{Hummingbird => HummingbirdLambda}/template.yaml (100%) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index b0ba8c0f..4eefa3f1 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -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', 'Hummingbird', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'StreamingFromEvent', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]" + examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'HummingbirdLambda', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'StreamingFromEvent', 'ServiceLifecycle+Postgres', 'Testing', 'Tutorial' ]" archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]" archive_plugin_enabled: true diff --git a/Examples/Hummingbird/.gitignore b/Examples/HummingbirdLambda/.gitignore similarity index 100% rename from Examples/Hummingbird/.gitignore rename to Examples/HummingbirdLambda/.gitignore diff --git a/Examples/Hummingbird/Package.swift b/Examples/HummingbirdLambda/Package.swift similarity index 100% rename from Examples/Hummingbird/Package.swift rename to Examples/HummingbirdLambda/Package.swift diff --git a/Examples/Hummingbird/README.md b/Examples/HummingbirdLambda/README.md similarity index 100% rename from Examples/Hummingbird/README.md rename to Examples/HummingbirdLambda/README.md diff --git a/Examples/Hummingbird/Sources/main.swift b/Examples/HummingbirdLambda/Sources/main.swift similarity index 100% rename from Examples/Hummingbird/Sources/main.swift rename to Examples/HummingbirdLambda/Sources/main.swift diff --git a/Examples/Hummingbird/template.yaml b/Examples/HummingbirdLambda/template.yaml similarity index 100% rename from Examples/Hummingbird/template.yaml rename to Examples/HummingbirdLambda/template.yaml