Restructure Examples folder (#387)

* Restructure Examples folder

* add README

* remove v1 examples

* swift format
This commit is contained in:
Sébastien Stormacq
2024-10-08 05:07:47 -04:00
committed by GitHub
parent 426e658414
commit db17a62e38
61 changed files with 389 additions and 2241 deletions
+1
View File
@@ -9,3 +9,4 @@ xcuserdata
Package.resolved
.serverless
.vscode
Makefile
+2
View File
@@ -0,0 +1,2 @@
samconfig.toml
Makefile
+55
View File
@@ -0,0 +1,55 @@
// swift-tools-version:6.0
import PackageDescription
// needed for CI to test the local version of the library
import class Foundation.ProcessInfo
import struct Foundation.URL
#if os(macOS)
let platforms: [PackageDescription.SupportedPlatform]? = [.macOS(.v15)]
#else
let platforms: [PackageDescription.SupportedPlatform]? = nil
#endif
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: platforms,
products: [
.executable(name: "APIGAtewayLambda", targets: ["APIGAtewayLambda"])
],
dependencies: [
// dependency on swift-aws-lambda-runtime is added dynamically below
// .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", branch: "main")
],
targets: [
.executableTarget(
name: "APIGAtewayLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
],
path: "."
)
]
)
if let localDepsPath = ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"],
localDepsPath != "",
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
let _ = v.isDirectory
{
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
package.dependencies += [
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
]
} else {
print("[INFO] LAMBDA_USE_LOCAL_DEPS is not pointing to your local swift-aws-lambda-runtime code")
print("[INFO] This project will compile against the main branch of the Lambda Runtime on GitHub")
package.dependencies += [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
]
}
+124
View File
@@ -0,0 +1,124 @@
# API Gateway
This is a simple example of an AWS Lambda function invoked through an Amazon API Gateway.
## Code
The Lambda function takes all HTTP headers it receives as input and returns them as output.
The code creates a `LambdaRuntime` struct. In it's simplest form, the initializer takes a function as argument. The function is the handler that will be invoked when the API Gateway receives an HTTP request.
The handler is `(event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response`. The function takes two arguments:
- the event argument is a `APIGatewayV2Request`. It is the parameter passed by the API Gateway. It contains all data passed in the HTTP request and some meta data.
- the context argument is a `Lambda Context`. It is a description of the runtime context.
The function must return a `APIGatewayV2Response`.
`APIGatewayV2Request` and `APIGatewayV2Response` are defined in the [Swift AWS Lambda Events](https://github.com/swift-server/swift-aws-lambda-events) library.
## Build & Package
To build the package, type the following commands.
```bash
swift build
swift package archive --disable-sandbox
```
If there is no error, there is a ZIP file ready to deploy.
The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/MyLambda/MyLambda.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 MyLambda \
--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 UR"
Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com
-----------------------------------------------------------------------------------------------------------------------------
```
## Invoke your Lambda function
To invoke the Lambda function, use this `curl` command line.
```bash
curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com
```
Be sure to replace the URL with the API Gateway endpoint returned in the previous step.
This should print a JSON similar to
```bash
{"version":"2.0","rawPath":"\/","isBase64Encoded":false,"rawQueryString":"","headers":{"user-agent":"curl\/8.7.1","accept":"*\/*","host":"a5q74es3k2.execute-api.us-east-1.amazonaws.com","content-length":"0","x-amzn-trace-id":"Root=1-66fb0388-691f744d4bd3c99c7436a78d","x-forwarded-port":"443","x-forwarded-for":"81.0.0.43","x-forwarded-proto":"https"},"requestContext":{"requestId":"e719cgNpoAMEcwA=","http":{"sourceIp":"81.0.0.43","path":"\/","protocol":"HTTP\/1.1","userAgent":"curl\/8.7.1","method":"GET"},"stage":"$default","apiId":"a5q74es3k2","time":"30\/Sep\/2024:20:01:12 +0000","timeEpoch":1727726472922,"domainPrefix":"a5q74es3k2","domainName":"a5q74es3k2.execute-api.us-east-1.amazonaws.com","accountId":"012345678901"}
```
If you have `jq` installed, you can use it to pretty print the output.
```bash
curl -s https://a5q74es3k2.execute-api.us-east-1.amazonaws.com | jq
{
"version": "2.0",
"rawPath": "/",
"requestContext": {
"domainPrefix": "a5q74es3k2",
"stage": "$default",
"timeEpoch": 1727726558220,
"http": {
"protocol": "HTTP/1.1",
"method": "GET",
"userAgent": "curl/8.7.1",
"path": "/",
"sourceIp": "81.0.0.43"
},
"apiId": "a5q74es3k2",
"accountId": "012345678901",
"requestId": "e72KxgsRoAMEMSA=",
"domainName": "a5q74es3k2.execute-api.us-east-1.amazonaws.com",
"time": "30/Sep/2024:20:02:38 +0000"
},
"rawQueryString": "",
"routeKey": "$default",
"headers": {
"x-forwarded-for": "81.0.0.43",
"user-agent": "curl/8.7.1",
"host": "a5q74es3k2.execute-api.us-east-1.amazonaws.com",
"accept": "*/*",
"x-amzn-trace-id": "Root=1-66fb03de-07533930192eaf5f540db0cb",
"content-length": "0",
"x-forwarded-proto": "https",
"x-forwarded-port": "443"
},
"isBase64Encoded": false
}
```
## Undeploy
When done testing, you can delete the infrastructure with this command.
```bash
sam delete
```
+40
View File
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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 AWSLambdaRuntime
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
let encoder = JSONEncoder()
let runtime = LambdaRuntime {
(event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response in
var header = HTTPHeaders()
context.logger.debug("HTTP API Message received")
header["content-type"] = "application/json"
// echo the request in the response
let data = try encoder.encode(event)
let response = String(decoding: data, as: Unicode.UTF8.self)
return APIGatewayV2Response(statusCode: .ok, headers: header, body: response)
}
try await runtime.run()
+31
View File
@@ -0,0 +1,31 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for QuoteService
Resources:
# Lambda function
APIGAtewayLambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGAtewayLambda/APIGAtewayLambda.zip
Timeout: 60
Handler: swift.bootstrap
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: trace
Events:
HttpApiEvent:
Type: HttpApi
Outputs:
# print API Gateway endpoint
APIGAtewayEndpoint:
Description: API Gateway endpoint UR"
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
-32
View File
@@ -1,32 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020 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 AWSLambdaRuntimeCore
import NIOCore
// If you would like to benchmark Swift's Lambda Runtime,
// use this example which is more performant.
// `EventLoopLambdaHandler` does not offload the Lambda processing to a separate thread
// while the closure-based handlers do.
@main
struct BenchmarkHandler: EventLoopLambdaHandler {
static func makeHandler(context: LambdaInitializationContext) -> EventLoopFuture<Self> {
context.eventLoop.makeSucceededFuture(BenchmarkHandler())
}
func handle(_ event: String, context: LambdaContext) -> EventLoopFuture<String> {
context.eventLoop.makeSucceededFuture("hello, world!")
}
}
-34
View File
@@ -1,34 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntimeCore", package: "swift-aws-lambda-runtime")
],
path: "."
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
-1
View File
@@ -1 +0,0 @@
.build
-3
View File
@@ -1,3 +0,0 @@
FROM swift:5.5-amazonlinux2
RUN yum -y install zip
-43
View File
@@ -1,43 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-samples",
platforms: [
.macOS(.v12)
],
products: [
// introductory example
.executable(name: "HelloWorld", targets: ["HelloWorld"]),
// good for benchmarking
.executable(name: "Benchmark", targets: ["Benchmark"]),
// demonstrate different types of error handling
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "Benchmark",
dependencies: [
.product(name: "AWSLambdaRuntimeCore", package: "swift-aws-lambda-runtime")
]
),
.executableTarget(
name: "HelloWorld",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
]
),
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
-184
View File
@@ -1,184 +0,0 @@
# Deployment Examples
This sample project is a collection of Lambda functions that demonstrates
how to write a simple Lambda function in Swift, and how to package and deploy it
to the AWS Lambda platform.
The scripts are prepared to work from the `Deployment` folder.
```
git clone https://github.com/swift-server/swift-aws-lambda-runtime.git
cd swift-aws-lambda-runtime/Examples/Deployment
```
Note: The example scripts assume you have [jq](https://stedolan.github.io/jq/download/) command line tool installed.
## Mac M1 Considerations
Lambdas will run on an x86 processor by default. Building a Lambda with an M1 will create an arm-based executable which will not run on an x86 processor. Here are a few options for building Swift Lambdas on an M1:
1. Configure the Lambda to run on the [Graviton2](https://aws.amazon.com/blogs/aws/aws-lambda-functions-powered-by-aws-graviton2-processor-run-your-functions-on-arm-and-get-up-to-34-better-price-performance/) Arm-based processor.
2. Build with the x86 architecture by specifying `--platform linux/amd64` in all Docker 'build' and 'run' commands in `build-and-package.sh`.
## Deployment instructions using AWS CLI
Steps to deploy this sample to AWS Lambda using the AWS CLI:
1. Login to AWS Console and create an AWS Lambda with the following settings:
* Runtime: Custom runtime
* Handler: Can be any string, does not matter in this case
2. Build, package and deploy the Lambda
```
./scripts/deploy.sh
```
Notes:
- This script assumes you have AWS CLI installed and credentials setup in `~/.aws/credentials`.
- The default lambda function name is `SwiftSample`. You can specify a different one updating `lambda_name` in `deploy.sh`
- Update `s3_bucket=swift-lambda-test` in `deploy.sh` before running (AWS S3 buckets require a unique global name)
- Both lambda function and S3 bucket must exist before deploying for the first time.
### Deployment instructions using AWS SAM (Serverless Application Model)
AWS [Serverless Application Model](https://aws.amazon.com/serverless/sam/) (SAM) is an open-source framework for building serverless applications. This framework allows you to easily deploy other AWS resources and more complex deployment mechanisms such a CI pipelines.
***Note:*** Deploying using SAM will automatically create resources within your AWS account. Charges may apply for these resources.
To use SAM to deploy this sample to AWS:
1. Install the AWS CLI by following the [instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html).
2. Install SAM CLI by following the [instructions](https://aws.amazon.com/serverless/sam/).
3. Build, package and deploy the Lambda
```
./scripts/sam-deploy.sh --guided
```
The script will ask you which sample Lambda you wish to deploy. It will then guide you through the SAM setup process.
```
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: swift-aws-lambda-runtime-sample
AWS Region [us-east-1]: <your-favourite-region>
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: Y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: Y
Save arguments to samconfig.toml [Y/n]: Y
```
If you said yes to confirm changes, SAM will ask you to accept changes to the infrastructure you are setting up. For more on this, see [Cloud Formation](https://aws.amazon.com/cloudformation/).
The `sam-deploy` script passes through any parameters to the SAM deploy command.
4. Subsequent deploys can just use the command minus the `guided` parameter:
```
./scripts/sam-deploy.sh
```
The script will ask you which sample Lambda you wish to deploy. If you are deploying a different sample lambda, the deploy process will pull down the previous Lambda.
SAM will still ask you to confirm changes if you said yes to that initially.
5. Testing
For the API Gateway sample:
The SAM template will provide an output labelled `LambdaApiGatewayEndpoint` which you can use to test the Lambda. For example:
```
curl <<LambdaApiGatewayEndpoint>>
```
***Warning:*** This SAM template is only intended as a sample and creates a publicly accessible HTTP endpoint.
For all other samples use the AWS Lambda console.
### Deployment instructions using Serverless Framework (serverless.com)
[Serverless framework](https://www.serverless.com/open-source/) (Serverless) is a provider agnostic, open-source framework for building serverless applications. This framework allows you to easily deploy other AWS resources and more complex deployment mechanisms such a CI pipelines. Serverless Framework offers solutions for not only deploying but also testing, monitoring, alerting, and security and is widely adopted by the industry and offers along the open-source version a paid one.
***Note:*** Deploying using Serverless will automatically create resources within your AWS account. Charges may apply for these resources.
To use Serverless to deploy this sample to AWS:
1. Install the AWS CLI by following the [instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html).
2. Install Serverless by following the [instructions](https://www.serverless.com/framework/docs/getting-started/).
If you already have installed be sure you have the latest version.
The examples have been tested with the version 1.72.0.
```
Serverless --version
Framework Core: 1.72.0 (standalone)
Plugin: 3.6.13
SDK: 2.3.1
Components: 2.30.12
```
3. Build, package and deploy the Lambda
```
./scripts/serverless-deploy.sh
```
The script will ask you which sample Lambda you wish to deploy.
The `serverless-deploy.sh` script passes through any parameters to the Serverless deploy command.
4. Testing
For the APIGateway sample:
The Serverless template will provide an endpoint which you can use to test the Lambda.
Outuput example:
```
...
...
Serverless: Stack update finished...
Service Information
service: apigateway-swift-aws
stage: dev
region: us-east-1
stack: apigateway-swift-aws-dev
resources: 12
api keys:
None
endpoints:
GET - https://r39lvhfng3.execute-api.us-east-1.amazonaws.com/api
functions:
httpGet: apigateway-swift-aws-dev-httpGet
layers:
None
Stack Outputs
HttpGetLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:XXXXXXXXX:function:apigateway-swift-aws-dev-httpGet:1
ServerlessDeploymentBucketName: apigateway-swift-aws-dev-serverlessdeploymentbuck-ud51msgcrj1e
HttpApiUrl: https://r39lvhfng3.execute-api.us-east-1.amazonaws.com
```
For example:
```
curl https://r39lvhfng3.execute-api.us-east-1.amazonaws.com/api
```
***Warning:*** This Serverless template is only intended as a sample and creates a publicly accessible HTTP endpoint.
For all other samples use the AWS Lambda console.
4. Remove
```
./scripts/serverless-remove.sh
```
The script will ask you which sample Lambda you wish to remove from the previous deployment.
@@ -1,32 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020 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 AWSLambdaRuntimeCore
import NIOCore
// If you would like to benchmark Swift's Lambda Runtime,
// use this example which is more performant.
// `EventLoopLambdaHandler` does not offload the Lambda processing to a separate thread
// while the closure-based handlers do.
@main
struct BenchmarkHandler: EventLoopLambdaHandler {
static func makeHandler(context: LambdaInitializationContext) -> EventLoopFuture<Self> {
context.eventLoop.makeSucceededFuture(BenchmarkHandler())
}
func handle(_ event: String, context: LambdaContext) -> EventLoopFuture<String> {
context.eventLoop.makeSucceededFuture("hello, world!")
}
}
@@ -1,23 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020 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 AWSLambdaRuntime
// introductory example, the obligatory "hello, world!"
@main
struct HelloWorldHandler: SimpleLambdaHandler {
func handle(_ event: String, context: LambdaContext) async throws -> String {
"hello, world"
}
}
@@ -1,14 +0,0 @@
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A sample SAM template for deploying Lambda functions.
Resources:
# Benchmark Function
benchmarkFunction:
Type: AWS::Serverless::Function
Properties:
Handler: Provided
Runtime: provided
CodeUri: ../../.build/lambda/Benchmark/lambda.zip
# Instructs new versions to be published to an alias named "live".
AutoPublishAlias: live
@@ -1,14 +0,0 @@
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A sample SAM template for deploying Lambda functions.
Resources:
# HelloWorld Function
helloWorldFunction:
Type: AWS::Serverless::Function
Properties:
Handler: Provided
Runtime: provided
CodeUri: ../../.build/lambda/HelloWorld/lambda.zip
# Instructs new versions to be published to an alias named "live".
AutoPublishAlias: live
@@ -1,39 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2020 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
##
##===----------------------------------------------------------------------===##
set -eu
executable=$1
workspace="$(pwd)/../.."
echo "-------------------------------------------------------------------------"
echo "preparing docker build image"
echo "-------------------------------------------------------------------------"
docker build . -t builder
echo "done"
echo "-------------------------------------------------------------------------"
echo "building \"$executable\" lambda"
echo "-------------------------------------------------------------------------"
docker run --rm -v "$workspace":/workspace -w /workspace/Examples/Deployment builder \
bash -cl "swift build --product $executable -c release"
echo "done"
echo "-------------------------------------------------------------------------"
echo "packaging \"$executable\" lambda"
echo "-------------------------------------------------------------------------"
docker run --rm -v "$workspace":/workspace -w /workspace/Examples/Deployment builder \
bash -cl "./scripts/package.sh $executable"
echo "done"
-38
View File
@@ -1,38 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2017-2018 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
##
##===----------------------------------------------------------------------===##
DIR="$(cd "$(dirname "$0")" && pwd)"
executables=( $(swift package dump-package | sed -e 's|: null|: ""|g' | jq '.products[] | (select(.type.executable)) | .name' | sed -e 's|"||g') )
if [[ ${#executables[@]} = 0 ]]; then
echo "no executables found"
exit 1
elif [[ ${#executables[@]} = 1 ]]; then
executable=${executables[0]}
elif [[ ${#executables[@]} > 1 ]]; then
echo "multiple executables found:"
for executable in ${executables[@]}; do
echo " * $executable"
done
echo ""
read -p "select which executables to deploy: " executable
fi
echo "-------------------------------------------------------------------------"
echo "configuration"
echo "-------------------------------------------------------------------------"
echo "current dir: $DIR"
echo "executable: $executable"
echo "-------------------------------------------------------------------------"
-43
View File
@@ -1,43 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2020 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
##
##===----------------------------------------------------------------------===##
set -eu
DIR="$(cd "$(dirname "$0")" && pwd)"
source $DIR/config.sh
workspace="$DIR/../.."
echo -e "\ndeploying $executable"
$DIR/build-and-package.sh "$executable"
echo "-------------------------------------------------------------------------"
echo "uploading \"$executable\" lambda to AWS S3"
echo "-------------------------------------------------------------------------"
read -p "S3 bucket name to upload zip file (must exist in AWS S3): " s3_bucket
s3_bucket=${s3_bucket:-swift-lambda-test} # default for easy testing
aws s3 cp ".build/lambda/$executable/lambda.zip" "s3://$s3_bucket/"
echo "-------------------------------------------------------------------------"
echo "updating AWS Lambda to use \"$executable\""
echo "-------------------------------------------------------------------------"
read -p "Lambda Function name (must exist in AWS Lambda): " lambda_name
lambda_name=${lambda_name:-SwiftSample} # default for easy testing
aws lambda update-function-code --function "$lambda_name" --s3-bucket "$s3_bucket" --s3-key lambda.zip
-28
View File
@@ -1,28 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2020 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
##
##===----------------------------------------------------------------------===##
set -eu
executable=$1
target=".build/lambda/$executable"
rm -rf "$target"
mkdir -p "$target"
cp ".build/release/$executable" "$target/"
# add the target deps based on ldd
ldd ".build/release/$executable" | grep swift | awk '{print $3}' | xargs cp -Lv -t "$target"
cd "$target"
ln -s "$executable" "bootstrap"
zip --symlinks lambda.zip *
-27
View File
@@ -1,27 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2017-2018 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
##
##===----------------------------------------------------------------------===##
DIR="$(cd "$(dirname "$0")" && pwd)"
source $DIR/config.sh
echo -e "\ndeploying $executable"
$DIR/build-and-package.sh "$executable"
echo "-------------------------------------------------------------------------"
echo "deploying using SAM"
echo "-------------------------------------------------------------------------"
sam deploy --template "./scripts/SAM/$executable-template.yml" $@
@@ -1,29 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2017-2018 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
##
##===----------------------------------------------------------------------===##
set -eu
DIR="$(cd "$(dirname "$0")" && pwd)"
source $DIR/config.sh
echo -e "\ndeploying $executable"
$DIR/build-and-package.sh "$executable"
echo "-------------------------------------------------------------------------"
echo "deploying using Serverless"
echo "-------------------------------------------------------------------------"
serverless deploy --config "./scripts/serverless/$executable-template.yml" --stage dev -v
@@ -1,27 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2017-2018 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
##
##===----------------------------------------------------------------------===##
set -eu
DIR="$(cd "$(dirname "$0")" && pwd)"
source $DIR/config.sh
echo -e "\nremoving $executable"
echo "-------------------------------------------------------------------------"
echo "removing using Serverless"
echo "-------------------------------------------------------------------------"
serverless remove --config "./scripts/serverless/$executable-template.yml" --stage dev -v
@@ -1,20 +0,0 @@
service: benchmark-swift-aws
package:
artifact: .build/lambda/Benchmark/lambda.zip
provider:
name: aws
runtime: provided
iamRoleStatements:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"
functions:
benchmarkFunction:
handler: Benchmark
memorySize: 128
@@ -1,20 +0,0 @@
service: helloworld-swift-aws
package:
artifact: .build/lambda/HelloWorld/lambda.zip
provider:
name: aws
runtime: provided
iamRoleStatements:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"
functions:
hello:
handler: HelloWorld
memorySize: 128
-34
View File
@@ -1,34 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
],
path: "."
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
-104
View File
@@ -1,104 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020 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 AWSLambdaRuntime
// MARK: - Run Lambda
@main
struct MyLambda: SimpleLambdaHandler {
func handle(_ request: Request, context: LambdaContext) async throws -> Response {
// switch over the error type "requested" by the request, and trigger such error accordingly
switch request.error {
// no error here!
case .none:
return Response(awsRequestID: context.requestID, requestID: request.requestID, status: .ok)
// trigger a "managed" error - domain specific business logic failure
case .managed:
return Response(awsRequestID: context.requestID, requestID: request.requestID, status: .error)
// trigger an "unmanaged" error - an unexpected Swift Error triggered while processing the request
case .unmanaged(let error):
throw UnmanagedError(description: error)
// trigger a "fatal" error - a panic type error which will crash the process
case .fatal:
fatalError("crash!")
}
}
}
// MARK: - Request and Response
struct Request: Codable {
let requestID: String
let error: Error
public init(requestID: String, error: Error? = nil) {
self.requestID = requestID
self.error = error ?? .none
}
public enum Error: Codable, RawRepresentable {
case none
case managed
case unmanaged(String)
case fatal
public init?(rawValue: String) {
switch rawValue {
case "none":
self = .none
case "managed":
self = .managed
case "fatal":
self = .fatal
default:
self = .unmanaged(rawValue)
}
}
public var rawValue: String {
switch self {
case .none:
return "none"
case .managed:
return "managed"
case .fatal:
return "fatal"
case .unmanaged(let error):
return error
}
}
}
}
struct Response: Codable {
let awsRequestID: String
let requestID: String
let status: Status
public init(awsRequestID: String, requestID: String, status: Status) {
self.awsRequestID = awsRequestID
self.requestID = requestID
self.status = status
}
public enum Status: Int, Codable {
case ok
case error
}
}
struct UnmanagedError: Error {
let description: String
}
-34
View File
@@ -1,34 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
],
path: "."
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
-286
View File
@@ -1,286 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020 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 AWSLambdaRuntime
import Dispatch
import Foundation
import Logging
#if canImport(FoundationNetworking) && canImport(FoundationXML)
import FoundationNetworking
import FoundationXML
#endif
// MARK: - Run Lambda
@main
struct MyLambda: LambdaHandler {
let calculator: ExchangeRatesCalculator
init(context: LambdaInitializationContext) async throws {
// the ExchangeRatesCalculator() can be reused over and over
self.calculator = ExchangeRatesCalculator()
}
func handle(_ event: Request, context: LambdaContext) async throws -> [Exchange] {
try await withCheckedThrowingContinuation { continuation in
self.calculator.run(logger: context.logger) { result in
switch result {
case .success(let exchanges):
continuation.resume(returning: exchanges)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
}
// MARK: - Business Logic
// This is a contrived example performing currency exchange rate lookup and conversion using URLSession and XML parsing
struct ExchangeRatesCalculator {
static let currencies = ["EUR", "USD", "JPY"]
static let currenciesEmojies = [
"EUR": "💶",
"JPY": "💴",
"USD": "💵",
]
let locale: Locale
let calendar: Calendar
init() {
// This is data from HMRC, the UK tax authority. Therefore we want to use their locale when interpreting data from the server.
self.locale = Locale(identifier: "en_GB")
// Use the UK calendar, not the system one.
var calendar = self.locale.calendar
calendar.timeZone = TimeZone(identifier: "UTC")!
self.calendar = calendar
}
func run(logger: Logger, callback: @escaping (Result<[Exchange], Swift.Error>) -> Void) {
let startDate = Date()
let months = (1...12).map {
self.calendar.date(byAdding: DateComponents(month: -$0), to: startDate)!
}
self.download(
logger: logger,
months: months,
monthIndex: months.startIndex,
currencies: Self.currencies,
state: [:]
) { result in
switch result {
case .failure(let error):
return callback(.failure(error))
case .success(let downloadedDataByMonth):
logger.debug("Downloads complete")
var result = [Exchange]()
var previousData: [String: Decimal?] = [:]
for (_, exchangeRateData) in downloadedDataByMonth.filter({ $1.period != nil }).sorted(by: {
$0.key < $1.key
}) {
for (currencyCode, rate) in exchangeRateData.ratesByCurrencyCode.sorted(by: { $0.key < $1.key }) {
if let rate = rate, let currencyEmoji = Self.currenciesEmojies[currencyCode] {
let change: Exchange.Change
switch previousData[currencyCode] {
case .some(.some(let previousRate)) where rate > previousRate:
change = .up
case .some(.some(let previousRate)) where rate < previousRate:
change = .down
case .some(.some(let previousRate)) where rate == previousRate:
change = .none
default:
change = .unknown
}
result.append(
Exchange(
date: exchangeRateData.period!.start,
from: .init(symbol: "GBP", emoji: "💷"),
to: .init(symbol: currencyCode, emoji: currencyEmoji),
rate: rate,
change: change
)
)
}
}
previousData = exchangeRateData.ratesByCurrencyCode
}
callback(.success(result))
}
}
}
private func download(
logger: Logger,
months: [Date],
monthIndex: Array<Date>.Index,
currencies: [String],
state: [Date: ExchangeRates],
callback: @escaping ((Result<[Date: ExchangeRates], Swift.Error>) -> Void)
) {
if monthIndex == months.count {
return callback(.success(state))
}
var newState = state
let month = months[monthIndex]
let url = self.exchangeRatesURL(forMonthContaining: month)
logger.debug("requesting exchange rate from \(url)")
let dataTask = URLSession.shared.dataTask(with: url) { data, _, error in
do {
guard let data = data else {
throw error!
}
let exchangeRates = try self.parse(data: data, currencyCodes: Set(currencies))
newState[month] = exchangeRates
logger.debug("Finished downloading month: \(month)")
if let period = exchangeRates.period {
logger.debug("Got data covering period: \(period)")
}
} catch {
return callback(.failure(error))
}
self.download(
logger: logger,
months: months,
monthIndex: monthIndex.advanced(by: 1),
currencies: currencies,
state: newState,
callback: callback
)
}
dataTask.resume()
}
private func parse(data: Data, currencyCodes: Set<String>) throws -> ExchangeRates {
let document = try XMLDocument(data: data)
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: "Etc/UTC")!
dateFormatter.dateFormat = "dd/MMM/yy"
let interval: DateInterval?
if let period = try document.nodes(forXPath: "/exchangeRateMonthList/@Period").first?.stringValue,
period.count == 26
{
// "01/Sep/2018 to 30/Sep/2018"
let startString = period[period.startIndex..<period.index(period.startIndex, offsetBy: 11)]
let to = period[startString.endIndex..<period.index(startString.endIndex, offsetBy: 4)]
let endString = period[to.endIndex..<period.index(to.endIndex, offsetBy: 11)]
if let startDate = dateFormatter.date(from: String(startString)),
let startDay = calendar.dateInterval(of: .day, for: startDate),
to == " to ",
let endDate = dateFormatter.date(from: String(endString)),
let endDay = calendar.dateInterval(of: .day, for: endDate)
{
interval = DateInterval(start: startDay.start, end: endDay.end)
} else {
interval = nil
}
} else {
interval = nil
}
let ratesByCurrencyCode: [String: Decimal?] = try Dictionary(
uniqueKeysWithValues: currencyCodes.map {
let xpathCurrency = $0.replacingOccurrences(of: "'", with: "&apos;")
if let rateString = try document.nodes(
forXPath:
"/exchangeRateMonthList/exchangeRate/currencyCode[text()='\(xpathCurrency)']/../rateNew/text()"
).first?.stringValue,
// We must parse the decimal data using the UK locale, not the system one.
let rate = Decimal(string: rateString, locale: self.locale)
{
return ($0, rate)
} else {
return ($0, nil)
}
}
)
return (period: interval, ratesByCurrencyCode: ratesByCurrencyCode)
}
private func makeUTCDateFormatter(dateFormat: String) -> DateFormatter {
let utcTimeZone = TimeZone(identifier: "UTC")!
let result = DateFormatter()
result.locale = Locale(identifier: "en_US_POSIX")
result.timeZone = utcTimeZone
result.dateFormat = dateFormat
return result
}
private func exchangeRatesURL(forMonthContaining date: Date) -> URL {
let exchangeRatesBaseURL = URL(string: "https://www.hmrc.gov.uk/softwaredevelopers/rates")!
let dateFormatter = self.makeUTCDateFormatter(dateFormat: "MMyy")
return exchangeRatesBaseURL.appendingPathComponent("exrates-monthly-\(dateFormatter.string(from: date)).xml")
}
private typealias ExchangeRates = (period: DateInterval?, ratesByCurrencyCode: [String: Decimal?])
private struct Error: Swift.Error, CustomStringConvertible {
let description: String
}
}
// MARK: - Request and Response
struct Request: Decodable {}
struct Exchange: Encodable {
@DateCoding
var date: Date
let from: Currency
let to: Currency
let rate: Decimal
let change: Change
struct Currency: Encodable {
let symbol: String
let emoji: String
}
enum Change: String, Encodable {
case up
case down
case none
case unknown
}
@propertyWrapper
public struct DateCoding: Encodable {
public let wrappedValue: Date
public init(wrappedValue: Date) {
self.wrappedValue = wrappedValue
}
func encode(to encoder: Encoder) throws {
let string = Self.dateFormatter.string(from: self.wrappedValue)
var container = encoder.singleValueContainer()
try container.encode(string)
}
private static var dateFormatter: ISO8601DateFormatter {
let dateFormatter = ISO8601DateFormatter()
dateFormatter.timeZone = TimeZone(identifier: "UTC")!
dateFormatter.formatOptions = [.withYear, .withMonth, .withDashSeparatorInDate]
return dateFormatter
}
}
}
-34
View File
@@ -1,34 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
],
path: "."
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
+4
View File
@@ -0,0 +1,4 @@
response.json
samconfig.toml
template.yaml
Makefile
+52
View File
@@ -0,0 +1,52 @@
// swift-tools-version:6.0
import PackageDescription
// needed for CI to test the local version of the library
import class Foundation.ProcessInfo
import struct Foundation.URL
#if os(macOS)
let platforms: [PackageDescription.SupportedPlatform]? = [.macOS(.v15)]
#else
let platforms: [PackageDescription.SupportedPlatform]? = nil
#endif
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: platforms,
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
// dependency on 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: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
],
path: "."
)
]
)
if let localDepsPath = ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"],
localDepsPath != "",
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
let _ = v.isDirectory
{
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
package.dependencies += [
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
]
} else {
print("[INFO] LAMBDA_USE_LOCAL_DEPS is not pointing to your local swift-aws-lambda-runtime code")
print("[INFO] This project will compile against the main branch of the Lambda Runtime on GitHub")
package.dependencies += [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
]
}
+74
View File
@@ -0,0 +1,74 @@
# Hello World
This is a simple example of an AWS Lambda function that takes a `String` as input parameter and returns a `String` as response.
## Code
The code creates a `LambdaRuntime` struct. In it's simplest form, the initializer takes a function as argument. The function is the handler that will be invoked when an event triggers the Lambda function.
The handler is `(event: String, context: LambdaContext)`. The function takes two arguments:
- the event argument is a `String`. It is the parameter passed when invoking the function.
- the context argument is a `Lambda Context`. It is a description of the runtime context.
The function return value will be encoded as your Lambda function response.
## Build & Package
To build & archive the package, type the following commands.
```bash
swift build
swift package archive --disable-sandbox
```
If there is no error, there is a ZIP file ready to deploy.
The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/MyLambda/MyLambda.zip`
## Deploy
Here is how to deploy using the `aws` command line.
```bash
aws lambda create-function \
--function-name MyLambda \
--zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/MyLambda/MyLambda.zip \
--runtime provided.al2 \
--handler provided \
--architectures arm64 \
--role arn:aws:iam::<YOUR_ACCOUNT_ID>:role/lambda_basic_execution
```
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`.
Be sure to replace <YOUR_ACCOUNT_ID> with your actual AWS account ID (for example: 012345678901).
## Invoke your Lambda function
To invoke the Lambda function, use this `aws` command line.
```bash
aws lambda invoke \
--function-name MyLambda \
--payload $(echo \"Seb\" | base64) \
out.txt && cat out.txt && rm out.txt
```
Note that the payload is expected to be a valid JSON string, hence the surroundings quotes (`"`).
This should output the following result.
```
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
"Hello Seb"
```
## Undeploy
When done testing, you can delete the Lambda function with this command.
```bash
aws lambda delete-function --function-name MyLambda
```
@@ -2,7 +2,7 @@
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2021 Apple Inc. and the SwiftAWSLambdaRuntime project authors
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
@@ -16,10 +16,9 @@ import AWSLambdaRuntime
// in this example we are receiving and responding with strings
@main
struct MyLambda: SimpleLambdaHandler {
func handle(_ input: String, context: LambdaContext) async throws -> String {
// as an example, respond with the input's reversed
String(input.reversed())
}
let runtime = LambdaRuntime {
(event: String, context: LambdaContext) in
"Hello \(event)"
}
try await runtime.run()
-34
View File
@@ -1,34 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2021 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 AWSLambdaRuntime
struct Request: Codable {
let body: String
}
struct Response: Codable {
let body: String
}
// in this example we are receiving and responding with codables. Request and Response above are examples of how to use
// codables to model your request and response objects
@main
struct MyLambda: SimpleLambdaHandler {
func handle(_ event: Request, context: LambdaContext) async throws -> Response {
// as an example, respond with the input event's reversed body
Response(body: String(event.body.reversed()))
}
}
-34
View File
@@ -1,34 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
],
path: "."
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Shared">
</FileRef>
<FileRef
location = "group:MyLambda">
</FileRef>
<FileRef
location = "group:MyApp/MyApp.xcodeproj">
</FileRef>
<FileRef
location = "group:README.md">
</FileRef>
</Workspace>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -1,366 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
7CD1174B26FE468F007DD17A /* MyApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD1174A26FE468F007DD17A /* MyApp.swift */; };
7CD1174D26FE468F007DD17A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD1174C26FE468F007DD17A /* ContentView.swift */; };
7CD1174F26FE4692007DD17A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7CD1174E26FE4692007DD17A /* Assets.xcassets */; };
7CD1175226FE4692007DD17A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7CD1175126FE4692007DD17A /* Preview Assets.xcassets */; };
7CD1175A26FE4F44007DD17A /* Shared in Frameworks */ = {isa = PBXBuildFile; productRef = 7CD1175926FE4F44007DD17A /* Shared */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
7CD1174726FE468F007DD17A /* MyApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MyApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
7CD1174A26FE468F007DD17A /* MyApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyApp.swift; sourceTree = "<group>"; };
7CD1174C26FE468F007DD17A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
7CD1174E26FE4692007DD17A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
7CD1175126FE4692007DD17A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
7CD1174426FE468F007DD17A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7CD1175A26FE4F44007DD17A /* Shared in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7CD1173E26FE468F007DD17A = {
isa = PBXGroup;
children = (
7CD1174926FE468F007DD17A /* MyApp */,
7CD1174826FE468F007DD17A /* Products */,
7CD1175826FE4F44007DD17A /* Frameworks */,
);
sourceTree = "<group>";
};
7CD1174826FE468F007DD17A /* Products */ = {
isa = PBXGroup;
children = (
7CD1174726FE468F007DD17A /* MyApp.app */,
);
name = Products;
sourceTree = "<group>";
};
7CD1174926FE468F007DD17A /* MyApp */ = {
isa = PBXGroup;
children = (
7CD1174A26FE468F007DD17A /* MyApp.swift */,
7CD1174C26FE468F007DD17A /* ContentView.swift */,
7CD1174E26FE4692007DD17A /* Assets.xcassets */,
7CD1175026FE4692007DD17A /* Preview Content */,
);
path = MyApp;
sourceTree = "<group>";
};
7CD1175026FE4692007DD17A /* Preview Content */ = {
isa = PBXGroup;
children = (
7CD1175126FE4692007DD17A /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
7CD1175826FE4F44007DD17A /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7CD1174626FE468F007DD17A /* MyApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7CD1175526FE4692007DD17A /* Build configuration list for PBXNativeTarget "MyApp" */;
buildPhases = (
7CD1174326FE468F007DD17A /* Sources */,
7CD1174426FE468F007DD17A /* Frameworks */,
7CD1174526FE468F007DD17A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MyApp;
packageProductDependencies = (
7CD1175926FE4F44007DD17A /* Shared */,
);
productName = MyApp;
productReference = 7CD1174726FE468F007DD17A /* MyApp.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7CD1173F26FE468F007DD17A /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1300;
LastUpgradeCheck = 1300;
TargetAttributes = {
7CD1174626FE468F007DD17A = {
CreatedOnToolsVersion = 13.0;
};
};
};
buildConfigurationList = 7CD1174226FE468F007DD17A /* Build configuration list for PBXProject "MyApp" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 7CD1173E26FE468F007DD17A;
productRefGroup = 7CD1174826FE468F007DD17A /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
7CD1174626FE468F007DD17A /* MyApp */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
7CD1174526FE468F007DD17A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7CD1175226FE4692007DD17A /* Preview Assets.xcassets in Resources */,
7CD1174F26FE4692007DD17A /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
7CD1174326FE468F007DD17A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7CD1174D26FE468F007DD17A /* ContentView.swift in Sources */,
7CD1174B26FE468F007DD17A /* MyApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
7CD1175326FE4692007DD17A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
7CD1175426FE4692007DD17A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7CD1175626FE4692007DD17A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"MyApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.apple.swift.MyApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
7CD1175726FE4692007DD17A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"MyApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.apple.swift.MyApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7CD1174226FE468F007DD17A /* Build configuration list for PBXProject "MyApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7CD1175326FE4692007DD17A /* Debug */,
7CD1175426FE4692007DD17A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7CD1175526FE4692007DD17A /* Build configuration list for PBXNativeTarget "MyApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7CD1175626FE4692007DD17A /* Debug */,
7CD1175726FE4692007DD17A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
7CD1175926FE4F44007DD17A /* Shared */ = {
isa = XCSwiftPackageProductDependency;
productName = Shared;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 7CD1173F26FE468F007DD17A /* Project object */;
}
@@ -1,98 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1,95 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020-2021 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 Shared
import SwiftUI
struct ContentView: View {
@State var name: String = ""
@State var password: String = ""
@State var response: String = ""
@State private var isLoading: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 20) {
TextField("Username", text: self.$name)
SecureField("Password", text: self.$password)
let inputIncomplete = self.name.isEmpty || self.password.isEmpty
Button {
Task {
self.isLoading = true
do {
self.response = try await self.register()
} catch {
self.response = error.localizedDescription
}
self.isLoading = false
}
} label: {
Text("Register")
.padding()
.foregroundColor(.white)
.background(.black)
.border(.black, width: 2)
.opacity(self.isLoading ? 0 : 1)
.overlay {
if self.isLoading {
ProgressView()
}
}
}
.disabled(inputIncomplete || self.isLoading)
.opacity(inputIncomplete ? 0.5 : 1)
Text(self.response)
}.padding(100)
}
func register() async throws -> String {
guard let url = URL(string: "http://127.0.0.1:7000/invoke") else {
fatalError("invalid url")
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
guard let jsonRequest = try? JSONEncoder().encode(Request(name: self.name, password: self.password)) else {
fatalError("encoding error")
}
request.httpBody = jsonRequest
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw CommunicationError(reason: "Invalid response, expected HTTPURLResponse.")
}
guard httpResponse.statusCode == 200 else {
throw CommunicationError(reason: "Invalid response code: \(httpResponse.statusCode)")
}
let jsonResponse = try JSONDecoder().decode(Response.self, from: data)
return jsonResponse.message
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct CommunicationError: LocalizedError {
let reason: String
var errorDescription: String? {
self.reason
}
}
@@ -1,24 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2021 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 SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
@@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1 +0,0 @@
.build
@@ -1,3 +0,0 @@
FROM swift:5.5-amazonlinux2
RUN yum -y install zip
@@ -1,27 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020-2021 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 AWSLambdaRuntime
import Shared
// set LOCAL_LAMBDA_SERVER_ENABLED env variable to "true" to start
// a local server simulator which will allow local debugging
@main
struct MyLambda: SimpleLambdaHandler {
func handle(_ request: Request, context: LambdaContext) async throws -> Response {
// TODO: something useful
Response(message: "Hello, \(request.name)!")
}
}
@@ -1,38 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "MyLambda",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha"),
.package(name: "Shared", path: "../Shared"),
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
.product(name: "Shared", package: "Shared"),
],
path: ".",
exclude: ["scripts/", "Dockerfile"]
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../../.."),
.package(name: "Shared", path: "../Shared"),
]
}
@@ -1,53 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2020 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
##
##===----------------------------------------------------------------------===##
set -eu
executable=MyLambda
lambda_name=SwiftSample
s3_bucket=swift-lambda-test
echo -e "\ndeploying $executable"
echo "-------------------------------------------------------------------------"
echo "preparing docker build image"
echo "-------------------------------------------------------------------------"
docker build . -t builder
echo "done"
echo "-------------------------------------------------------------------------"
echo "building \"$executable\" lambda"
echo "-------------------------------------------------------------------------"
docker run --rm -v `pwd`/../../..:/workspace -w /workspace/Examples/LocalDebugging/MyLambda builder \
bash -cl "swift build --product $executable -c release"
echo "done"
echo "-------------------------------------------------------------------------"
echo "packaging \"$executable\" lambda"
echo "-------------------------------------------------------------------------"
docker run --rm -v `pwd`:/workspace -w /workspace builder \
bash -cl "./scripts/package.sh $executable"
echo "done"
echo "-------------------------------------------------------------------------"
echo "uploading \"$executable\" lambda to s3"
echo "-------------------------------------------------------------------------"
aws s3 cp .build/lambda/$executable/lambda.zip s3://$s3_bucket/
echo "-------------------------------------------------------------------------"
echo "updating \"$lambda_name\" to latest \"$executable\""
echo "-------------------------------------------------------------------------"
aws lambda update-function-code --function $lambda_name --s3-bucket $s3_bucket --s3-key lambda.zip
@@ -1,28 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright (c) 2020 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
##
##===----------------------------------------------------------------------===##
set -eu
executable=$1
target=".build/lambda/$executable"
rm -rf "$target"
mkdir -p "$target"
cp ".build/release/$executable" "$target/"
# add the target deps based on ldd
ldd ".build/release/$executable" | grep swift | awk '{print $3}' | xargs cp -Lv -t "$target"
cd "$target"
ln -s "$executable" "bootstrap"
zip --symlinks lambda.zip *
-35
View File
@@ -1,35 +0,0 @@
# Local Debugging Example
This sample project demonstrates how to write a simple Lambda function in Swift,
and how to use local debugging techniques that simulate how the Lambda function
would be invoked by the AWS Lambda Runtime engine.
The example includes an Xcode workspace with three modules:
1. [MyApp](MyApp) is a SwiftUI iOS application that calls the Lambda function.
2. [MyLambda](MyLambda) is a SwiftPM executable package for the Lambda function.
3. [Shared](Shared) is a SwiftPM library package used for shared code between the iOS application and the Lambda function,
such as the Request and Response model objects.
The local debugging experience is achieved by running the Lambda function in the context of the
debug-only local lambda engine simulator which starts a local HTTP server enabling the communication
between the iOS application and the Lambda function over HTTP.
To try out this example, open the workspace in Xcode and "run" the two targets,
using the relevant `MyLambda` and `MyApp` Xcode schemes.
Start with running the `MyLambda` target.
* Switch to the `MyLambda` scheme and select the "My Mac" destination
* Set the `LOCAL_LAMBDA_SERVER_ENABLED` environment variable to `true` by editing the `MyLambda` scheme Run/Arguments options.
* Hit `Run`
* Once it is up you should see a log message in the Xcode console saying
`LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke`
which means the local emulator is up and receiving traffic on port `7000` and expecting events on the `/invoke` endpoint.
Continue to run the `MyApp` target
* Switch to the `MyApp` scheme and select a simulator destination.
* Hit `Run`
* Once up, the application's UI should appear in the simulator allowing you
to interact with it.
Once both targets are running, set up breakpoints in the iOS application or Lambda function to observe the system behavior.
@@ -1,21 +0,0 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Shared",
products: [
.library(name: "Shared", targets: ["Shared"])
],
dependencies: [],
targets: [
.target(
name: "Shared",
dependencies: [],
resources: [
.process("Resources")
]
)
]
)
@@ -1 +0,0 @@
{}
@@ -1,35 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2020 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
//
//===----------------------------------------------------------------------===//
public struct Request: Codable, CustomStringConvertible {
public let name: String
public let password: String
public init(name: String, password: String) {
self.name = name
self.password = password
}
public var description: String {
"name: \(self.name), password: ***"
}
}
public struct Response: Codable {
public let message: String
public init(message: String) {
self.message = message
}
}
-28
View File
@@ -1,28 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2021 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 AWSLambdaRuntime
import Foundation
// in this example we are reading from a bundled resource and responding with the contents
@main
struct MyLambda: SimpleLambdaHandler {
func handle(_ input: String, context: LambdaContext) async throws -> String {
guard let fileURL = Bundle.module.url(forResource: "hello", withExtension: "txt") else {
fatalError("no file url")
}
return try String(contentsOf: fileURL)
}
}
-37
View File
@@ -1,37 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
],
path: ".",
resources: [
.process("hello.txt")
]
)
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
-1
View File
@@ -1 +0,0 @@
Hello, World!
-36
View File
@@ -1,36 +0,0 @@
// swift-tools-version:5.7
import PackageDescription
import class Foundation.ProcessInfo // needed for CI to test the local version of the library
let package = Package(
name: "swift-aws-lambda-runtime-example",
platforms: [
.macOS(.v12)
],
products: [
.executable(name: "MyLambda", targets: ["MyLambda"])
],
dependencies: [
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "1.0.0-alpha")
],
targets: [
.executableTarget(
name: "MyLambda",
dependencies: [
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
.product(name: "AWSLambdaTesting", package: "swift-aws-lambda-runtime"),
],
path: "Sources"
),
.testTarget(name: "MyLambdaTests", dependencies: ["MyLambda"], path: "Tests"),
]
)
// for CI to test the local version of the library
if ProcessInfo.processInfo.environment["LAMBDA_USE_LOCAL_DEPS"] != nil {
package.dependencies = [
.package(name: "swift-aws-lambda-runtime", path: "../..")
]
}
-25
View File
@@ -1,25 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2021 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 AWSLambdaRuntime
// in this example we are receiving and responding with strings
@main
struct MyLambda: SimpleLambdaHandler {
func handle(_ event: String, context: LambdaContext) async throws -> String {
// as an example, respond with the event's reversed body
String(event.reversed())
}
}
-27
View File
@@ -1,27 +0,0 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2021 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 AWSLambdaRuntime
import AWSLambdaTesting
import XCTest
@testable import MyLambda
class LambdaTest: XCTestCase {
func testIt() async throws {
let input = UUID().uuidString
let result = try await Lambda.test(MyLambda.self, with: input)
XCTAssertEqual(result, String(input.reversed()))
}
}