mirror of
https://github.com/swift-server/swift-aws-lambda-runtime.git
synced 2026-05-03 07:22:27 +00:00
Restructure Examples folder (#387)
* Restructure Examples folder * add README * remove v1 examples * swift format
This commit is contained in:
committed by
GitHub
parent
426e658414
commit
db17a62e38
@@ -9,3 +9,4 @@ xcuserdata
|
||||
Package.resolved
|
||||
.serverless
|
||||
.vscode
|
||||
Makefile
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
samconfig.toml
|
||||
Makefile
|
||||
@@ -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")
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
```
|
||||
@@ -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()
|
||||
@@ -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"
|
||||
@@ -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,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 +0,0 @@
|
||||
.build
|
||||
@@ -1,3 +0,0 @@
|
||||
FROM swift:5.5-amazonlinux2
|
||||
|
||||
RUN yum -y install zip
|
||||
@@ -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: "../..")
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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 "-------------------------------------------------------------------------"
|
||||
@@ -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
|
||||
@@ -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 *
|
||||
@@ -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
|
||||
@@ -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,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
|
||||
}
|
||||
@@ -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,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: "'")
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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: "../..")
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
response.json
|
||||
samconfig.toml
|
||||
template.yaml
|
||||
Makefile
|
||||
@@ -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")
|
||||
]
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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()))
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
-6
@@ -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 *
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 +0,0 @@
|
||||
Hello, World!
|
||||
@@ -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: "../..")
|
||||
]
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user