├── .devcontainer └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ └── issue-report.yml ├── PULL_REQUEST_TEMPLATE.md ├── release.yml └── workflows │ ├── integration_tests.yml │ ├── pull_request.yml │ └── scripts │ ├── check-archive-plugin.sh │ ├── check-link-foundation.sh │ └── integration_tests.sh ├── .gitignore ├── .licenseignore ├── .mailmap ├── .spi.yml ├── .swift-format ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.txt ├── Examples ├── APIGateway+LambdaAuthorizer │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ ├── APIGatewayLambda │ │ │ └── main.swift │ │ └── AuthorizerLambda │ │ │ └── main.swift │ └── template.yaml ├── APIGateway │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── main.swift │ └── template.yaml ├── BackgroundTasks │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ └── Sources │ │ └── main.swift ├── CDK │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── main.swift │ └── infra │ │ ├── .gitignore │ │ ├── .npmignore │ │ ├── README.md │ │ ├── bin │ │ └── deploy.ts │ │ ├── cdk.json │ │ ├── lib │ │ └── lambda-api-project-stack.ts │ │ ├── package-lock.json │ │ ├── package.json │ │ └── tsconfig.json ├── HelloJSON │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ └── Sources │ │ └── main.swift ├── HelloWorld │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ └── Sources │ │ └── main.swift ├── README.md ├── ResourcesPackaging │ ├── .gitignore │ ├── Package.swift │ ├── Sources │ │ └── main.swift │ └── hello.txt ├── S3EventNotifier │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ └── Sources │ │ └── main.swift ├── S3_AWSSDK │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── main.swift │ └── template.yaml ├── S3_Soto │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── main.swift │ └── template.yaml ├── Streaming │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── main.swift │ └── template.yaml ├── Testing │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ ├── Business.swift │ │ └── main.swift │ ├── Tests │ │ ├── BusinessTests.swift │ │ ├── HandlerTests.swift │ │ └── event.json │ └── template.yaml ├── Tutorial │ ├── .gitignore │ ├── Package.swift │ └── Sources │ │ └── main.swift └── _MyFirstFunction │ ├── .gitignore │ ├── clean.sh │ └── create_and_deploy_function.sh ├── LICENSE.txt ├── NOTICE.txt ├── Package.swift ├── Package@swift-6.0.swift ├── Plugins └── AWSLambdaPackager │ ├── Plugin.swift │ └── PluginUtils.swift ├── SECURITY.md ├── Sources ├── AWSLambdaRuntime │ ├── ControlPlaneRequest.swift │ ├── ControlPlaneRequestEncoder.swift │ ├── Docs.docc │ │ ├── Deployment.md │ │ ├── Documentation.md │ │ ├── Proposals │ │ │ └── 0001-v2-api.md │ │ ├── Resources │ │ │ ├── code │ │ │ │ ├── .shellcheckrc │ │ │ │ ├── 03-01-01-package-init.sh │ │ │ │ ├── 03-01-02-package-init.sh │ │ │ │ ├── 03-01-03-package-init.sh │ │ │ │ ├── 03-01-04-package-init.sh │ │ │ │ ├── 03-02-01-package.swift │ │ │ │ ├── 03-02-02-package.swift │ │ │ │ ├── 03-02-03-package.swift │ │ │ │ ├── 03-02-04-package.swift │ │ │ │ ├── 03-02-05-package.swift │ │ │ │ ├── 03-03-01-main.swift │ │ │ │ ├── 03-03-02-main.swift │ │ │ │ ├── 03-03-03-main.swift │ │ │ │ ├── 03-03-04-main.swift │ │ │ │ ├── 03-03-05-main.swift │ │ │ │ ├── 03-03-06-main.swift │ │ │ │ ├── 03-03-07-main.swift │ │ │ │ ├── 03-04-02-console-output.sh │ │ │ │ ├── 03-04-03-curl.sh │ │ │ │ ├── 03-04-04-curl.sh │ │ │ │ ├── 03-04-06-terminal.sh │ │ │ │ ├── 03-04-07-terminal.sh │ │ │ │ ├── 04-01-02-plugin-archive.sh │ │ │ │ ├── 04-01-03-plugin-archive.sh │ │ │ │ ├── 04-01-04-plugin-archive.sh │ │ │ │ ├── 04-03-01-aws-cli.sh │ │ │ │ ├── 04-03-02-lambda-invoke-hidden.sh │ │ │ │ ├── 04-03-02-lambda-invoke.sh │ │ │ │ ├── 04-03-03-lambda-invoke.sh │ │ │ │ ├── 04-03-04-lambda-invoke.sh │ │ │ │ └── 04-03-05-lambda-invoke.sh │ │ │ ├── deployment │ │ │ │ ├── console-10-regions.png │ │ │ │ ├── console-20-dashboard.png │ │ │ │ ├── console-30-create-function.png │ │ │ │ ├── console-40-select-zip-file.png │ │ │ │ ├── console-50-upload-zip.png │ │ │ │ ├── console-60-prepare-test-event.png │ │ │ │ ├── console-70-view-invocation-response.png │ │ │ │ ├── console-80-delete-function.png │ │ │ │ └── console-80-delete-role.png │ │ │ └── tutorials │ │ │ │ ├── 00-swift_on_lambda.png │ │ │ │ ├── 01-swift_on_lambda.png │ │ │ │ ├── 03-01-terminal-package-init.png │ │ │ │ ├── 03-01-xcode@2x.png │ │ │ │ ├── 03-01-xcode~dark@2x.png │ │ │ │ ├── 03-02-swift-package-manager.png │ │ │ │ ├── 03-03-swift-code-xcode.png │ │ │ │ ├── 03-04-01-compile-run@2x.png │ │ │ │ ├── 03-04-01-compile-run~dark@2x.png │ │ │ │ ├── 03-04-test-locally.png │ │ │ │ ├── 03-swift_on_lambda.png │ │ │ │ ├── 04-01-01-docker-started@2x.png │ │ │ │ ├── 04-01-compile-for-linux.png │ │ │ │ ├── 04-02-01-console-login@2x.png │ │ │ │ ├── 04-02-02-console-login@2x.png │ │ │ │ ├── 04-02-03-select-region@2x.png │ │ │ │ ├── 04-02-04-select-lambda@2x.png │ │ │ │ ├── 04-02-04-select-lambda~dark@2x.png │ │ │ │ ├── 04-02-05-create-function@2x.png │ │ │ │ ├── 04-02-05-create-function~dark@2x.png │ │ │ │ ├── 04-02-06-create-function@2x.png │ │ │ │ ├── 04-02-06-create-function~dark@2x.png │ │ │ │ ├── 04-02-07-upload-zip@2x.png │ │ │ │ ├── 04-02-07-upload-zip~dark@2x.png │ │ │ │ ├── 04-02-08-upload-zip@2x.png │ │ │ │ ├── 04-02-08-upload-zip~dark@2x.png │ │ │ │ ├── 04-02-09-test-lambda@2x.png │ │ │ │ ├── 04-02-09-test-lambda~dark@2x.png │ │ │ │ ├── 04-02-10-test-lambda-result@2x.png │ │ │ │ ├── 04-02-10-test-lambda-result~dark@2x.png │ │ │ │ ├── 04-02-create-lambda.png │ │ │ │ ├── 04-03-invoke-lambda.png │ │ │ │ └── 04-swift_on_lambda.png │ │ ├── quick-setup.md │ │ └── tutorials │ │ │ ├── 01-overview.tutorial │ │ │ ├── 02-what-is-lambda.tutorial │ │ │ ├── 03-prerequisites.tutorial │ │ │ ├── 03-write-function.tutorial │ │ │ ├── 04-deploy-function.tutorial │ │ │ └── table-of-content.tutorial │ ├── FoundationSupport │ │ ├── Context+Foundation.swift │ │ ├── Lambda+JSON.swift │ │ └── Vendored │ │ │ ├── ByteBuffer-foundation.swift │ │ │ └── JSON+ByteBuffer.swift │ ├── Lambda+Codable.swift │ ├── Lambda+LocalServer.swift │ ├── Lambda.swift │ ├── LambdaContext.swift │ ├── LambdaHandlers.swift │ ├── LambdaRequestID.swift │ ├── LambdaRuntime+ServiceLifecycle.swift │ ├── LambdaRuntime.swift │ ├── LambdaRuntimeClient.swift │ ├── LambdaRuntimeClientProtocol.swift │ ├── LambdaRuntimeError.swift │ └── Utils.swift └── MockServer │ └── MockHTTPServer.swift ├── Tests └── AWSLambdaRuntimeTests │ ├── CollectEverythingLogHandler.swift │ ├── ControlPlaneRequestEncoderTests.swift │ ├── InvocationTests.swift │ ├── LambdaMockClient.swift │ ├── LambdaRequestIDTests.swift │ ├── LambdaRunLoopTests.swift │ ├── LambdaRuntimeClientTests.swift │ ├── MockLambdaServer.swift │ ├── NewLambda+CodableTests.swift │ ├── Utils.swift │ └── UtilsTest.swift ├── projects.md ├── readme.md └── scripts ├── linux_performance_setup.sh ├── performance_test.sh ├── ubuntu-install-swift.sh └── ubuntu-test-plugin.sh /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Swift", 3 | "image": "swift:6.0", 4 | "features": { 5 | "ghcr.io/devcontainers/features/common-utils:2": { 6 | "installZsh": "false", 7 | "username": "vscode", 8 | "upgradePackages": "false" 9 | }, 10 | "ghcr.io/devcontainers/features/git:1": { 11 | "version": "os-provided", 12 | "ppa": "false" 13 | } 14 | }, 15 | "runArgs": [ 16 | "--cap-add=SYS_PTRACE", 17 | "--security-opt", 18 | "seccomp=unconfined" 19 | ], 20 | // Configure tool-specific properties. 21 | "customizations": { 22 | // Configure properties specific to VS Code. 23 | "vscode": { 24 | // Set *default* container specific settings.json values on container create. 25 | "settings": { 26 | "lldb.library": "/usr/lib/liblldb.so" 27 | }, 28 | // Add the IDs of extensions you want installed when the container is created. 29 | "extensions": [ 30 | "sswg.swift-lang" 31 | ] 32 | } 33 | }, 34 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 35 | // "forwardPorts": [], 36 | 37 | // Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 38 | "remoteUser": "vscode" 39 | } 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-report.yml: -------------------------------------------------------------------------------- 1 | name: Swift AWS Lambda SDK issue 2 | description: File an issue report with the usage of the Swift AWS Lambda Runtime 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: "Thanks for taking the time to fill out this issue report" 7 | - type: textarea 8 | id: expected-behavior 9 | attributes: 10 | label: Expected behavior 11 | description: What you expected to happen? 12 | placeholder: Describe with your own words the expected result 13 | validations: 14 | required: true 15 | - type: textarea 16 | id: what-happend 17 | attributes: 18 | label: Actual behavior 19 | description: What actually happened 20 | placeholder: Describe 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: steps-to-reproduce 25 | attributes: 26 | label: Steps to reproduce 27 | description: List the steps followed to reproduce the behaviour you are reporting 28 | placeholder: | 29 | 1. First I... 30 | 2. Then... 31 | 3. Finally... 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: code-snippet 36 | attributes: 37 | label: If possible, minimal yet complete reproducer code (or URL to code) 38 | description: List the steps followed to reproduce the behaviour you are reporting 39 | placeholder: | 40 | You can add any relevant code snippet that you consider or an URL to code. 41 | 42 | URL could be a link to a GitHub Gist, for example 43 | validations: 44 | required: false 45 | - type: input 46 | id: swift-aws-lambda-runtime-version 47 | attributes: 48 | label: What version of this project (`swift-aws-lambda-runtime`) are you using? 49 | description: The release, branch or commit hash related with this issue. 50 | placeholder: 1.0.0-alpha.1 51 | validations: 52 | required: true 53 | - type: textarea 54 | id: swift-version 55 | attributes: 56 | label: Swift version 57 | description: Swift environment version. 58 | placeholder: | 59 | Open a Terminal and execute the following command 60 | 61 | swift --version && uname -a 62 | validations: 63 | required: true 64 | - type: input 65 | id: amazon-linux-2-version 66 | attributes: 67 | label: Amazon Linux 2 docker image version 68 | description: The docker image tag used to archive the lambda, if available. 69 | placeholder: 5.7.3-amazonlinux2 70 | validations: 71 | required: false 72 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | _[One line description of your change]_ 2 | 3 | ### Motivation: 4 | 5 | _[Explain here the context, and why you're making that change. What is the problem you're trying to solve.]_ 6 | 7 | ### Modifications: 8 | 9 | _[Describe the modifications you've done.]_ 10 | 11 | ### Result: 12 | 13 | _[After your change, what will change.]_ 14 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | categories: 3 | - title: SemVer Major 4 | labels: 5 | - ⚠️ semver/major 6 | - title: SemVer Minor 7 | labels: 8 | - 🆕 semver/minor 9 | - title: SemVer Patch 10 | labels: 11 | - 🔨 semver/patch 12 | - title: Other Changes 13 | labels: 14 | - semver/none 15 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: PR 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened, synchronize] 6 | 7 | jobs: 8 | soundness: 9 | name: Soundness 10 | uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main 11 | with: 12 | license_header_check_project_name: "SwiftAWSLambdaRuntime" 13 | shell_check_enabled: true 14 | python_lint_check_enabled: true 15 | api_breakage_check_container_image: "swiftlang/swift:nightly-6.1-jammy" 16 | docs_check_container_image: "swift:6.0-noble" 17 | format_check_container_image: "swiftlang/swift:nightly-6.1-jammy" 18 | yamllint_check_enabled: true 19 | 20 | unit-tests: 21 | name: Unit tests 22 | uses: apple/swift-nio/.github/workflows/unit_tests.yml@main 23 | with: 24 | linux_5_9_enabled: false 25 | linux_5_10_enabled: false 26 | linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error" 27 | linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error" 28 | 29 | integration-tests: 30 | name: Integration Tests 31 | uses: ./.github/workflows/integration_tests.yml 32 | with: 33 | name: "Integration tests" 34 | examples_enabled: true 35 | matrix_linux_command: "LAMBDA_USE_LOCAL_DEPS=../.. swift build" 36 | # We pass the list of examples here, but we can't pass an array as argument 37 | # Instead, we pass a String with a valid JSON array. 38 | # The workaround is mentioned here https://github.com/orgs/community/discussions/11692 39 | examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'Testing', 'Tutorial' ]" 40 | archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]" 41 | archive_plugin_enabled: true 42 | 43 | swift-6-language-mode: 44 | name: Swift 6 Language Mode 45 | uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main 46 | 47 | semver-label-check: 48 | name: Semantic Version label check 49 | runs-on: ubuntu-latest 50 | timeout-minutes: 1 51 | steps: 52 | - name: Checkout repository 53 | uses: actions/checkout@v4 54 | with: 55 | persist-credentials: false 56 | - name: Check for Semantic Version label 57 | uses: apple/swift-nio/.github/actions/pull_request_semver_label_checker@main 58 | 59 | # until there is a support for musl in swiftlang/github-workflows 60 | # https://github.com/swiftlang/github-workflows/issues/34 61 | musl: 62 | runs-on: ubuntu-latest 63 | container: swift:6.0.2-noble 64 | timeout-minutes: 30 65 | steps: 66 | - name: Check out code 67 | uses: actions/checkout@v4 68 | - name: Install SDK 69 | run: swift sdk install https://download.swift.org/swift-6.0.2-release/static-sdk/swift-6.0.2-RELEASE/swift-6.0.2-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz --checksum aa5515476a403797223fc2aad4ca0c3bf83995d5427fb297cab1d93c68cee075 70 | - name: Build 71 | run: swift build --swift-sdk x86_64-swift-linux-musl 72 | -------------------------------------------------------------------------------- /.github/workflows/scripts/check-archive-plugin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftAWSLambdaRuntime open source project 5 | ## 6 | ## Copyright (c) 2017-2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | log() { printf -- "** %s\n" "$*" >&2; } 17 | error() { printf -- "** ERROR: %s\n" "$*" >&2; } 18 | fatal() { error "$@"; exit 1; } 19 | 20 | test -n "${EXAMPLE:-}" || fatal "EXAMPLE unset" 21 | 22 | OUTPUT_DIR=.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager 23 | OUTPUT_FILE=${OUTPUT_DIR}/MyLambda/bootstrap 24 | ZIP_FILE=${OUTPUT_DIR}/MyLambda/MyLambda.zip 25 | 26 | pushd "Examples/${EXAMPLE}" || exit 1 27 | 28 | # package the example (docker and swift toolchain are installed on the GH runner) 29 | LAMBDA_USE_LOCAL_DEPS=../.. swift package archive --allow-network-connections docker || exit 1 30 | 31 | # did the plugin generated a Linux binary? 32 | [ -f "${OUTPUT_FILE}" ] 33 | file "${OUTPUT_FILE}" | grep --silent ELF 34 | 35 | # did the plugin created a ZIP file? 36 | [ -f "${ZIP_FILE}" ] 37 | 38 | # does the ZIP file contain the bootstrap? 39 | unzip -l "${ZIP_FILE}" | grep --silent bootstrap 40 | 41 | # if EXAMPLE is ResourcesPackaging, check if the ZIP file contains hello.txt 42 | if [ "$EXAMPLE" == "ResourcesPackaging" ]; then 43 | echo "Checking if resource was added to the ZIP file" 44 | unzip -l "${ZIP_FILE}" | grep --silent hello.txt 45 | SUCCESS=$? 46 | if [ "$SUCCESS" -eq 1 ]; then 47 | log "❌ Resource not found." && exit 1 48 | else 49 | log "✅ Resource found." 50 | fi 51 | fi 52 | 53 | echo "✅ The archive plugin is OK with example ${EXAMPLE}" 54 | popd || exit 1 55 | -------------------------------------------------------------------------------- /.github/workflows/scripts/check-link-foundation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftAWSLambdaRuntime open source project 5 | ## 6 | ## Copyright (c) 2017-2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | log() { printf -- "** %s\n" "$*" >&2; } 17 | error() { printf -- "** ERROR: %s\n" "$*" >&2; } 18 | fatal() { error "$@"; exit 1; } 19 | 20 | EXAMPLE=APIGateway 21 | OUTPUT_DIR=.build/release 22 | OUTPUT_FILE=${OUTPUT_DIR}/APIGatewayLambda 23 | LIBS_TO_CHECK="libFoundation.so libFoundationInternationalization.so lib_FoundationICU.so" 24 | 25 | pushd Examples/${EXAMPLE} || fatal "Failed to change directory to Examples/${EXAMPLE}." 26 | 27 | # recompile the example without the --static-swift-stdlib flag 28 | LAMBDA_USE_LOCAL_DEPS=../.. swift build -c release -Xlinker -s || fatal "Failed to build the example." 29 | 30 | # check if the binary exists 31 | if [ ! -f "${OUTPUT_FILE}" ]; then 32 | error "❌ ${OUTPUT_FILE} does not exist." 33 | fi 34 | 35 | # Checking for Foundation or ICU dependencies 36 | echo "Checking for Foundation or ICU dependencies in ${OUTPUT_DIR}/${OUTPUT_FILE}." 37 | LIBRARIES=$(ldd ${OUTPUT_FILE} | awk '{print $1}') 38 | for LIB in ${LIBS_TO_CHECK}; do 39 | echo -n "Checking for ${LIB}... " 40 | 41 | # check if the binary has a dependency on Foundation or ICU 42 | echo "${LIBRARIES}" | grep "${LIB}" # return 1 if not found 43 | 44 | # 1 is success (grep failed to find the lib), 0 is failure (grep successly found the lib) 45 | SUCCESS=$? 46 | if [ "$SUCCESS" -eq 0 ]; then 47 | log "❌ ${LIB} found." && break 48 | else 49 | log "✅ ${LIB} not found." 50 | fi 51 | done 52 | 53 | popd || fatal "Failed to change directory back to the root directory." 54 | 55 | # exit code is the opposite of the grep exit code 56 | if [ "$SUCCESS" -eq 0 ]; then 57 | fatal "❌ At least one foundation lib was found, reporting the error." 58 | else 59 | log "✅ No foundation lib found, congrats!" && exit 0 60 | fi -------------------------------------------------------------------------------- /.github/workflows/scripts/integration_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftAWSLambdaRuntime open source project 5 | ## 6 | ## Copyright (c) 2017-2018 Apple Inc. and the SwiftAWSLambdaRuntime project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -euo pipefail 17 | 18 | log() { printf -- "** %s\n" "$*" >&2; } 19 | error() { printf -- "** ERROR: %s\n" "$*" >&2; } 20 | fatal() { error "$@"; exit 1; } 21 | 22 | SWIFT_VERSION=$(swift --version) 23 | test -n "${SWIFT_VERSION:-}" || fatal "SWIFT_VERSION unset" 24 | test -n "${COMMAND:-}" || fatal "COMMAND unset" 25 | test -n "${EXAMPLE:-}" || fatal "EXAMPLE unset" 26 | 27 | pushd Examples/"$EXAMPLE" > /dev/null 28 | 29 | log "Running command with Swift $SWIFT_VERSION" 30 | eval "$COMMAND" 31 | 32 | popd 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.build 3 | *.index-build 4 | /.xcodeproj 5 | *.pem 6 | .podspecs 7 | .swiftpm 8 | .swift-version 9 | xcuserdata 10 | Package.resolved 11 | .serverless 12 | .vscode 13 | Makefile 14 | .devcontainer -------------------------------------------------------------------------------- /.licenseignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .licenseignore 3 | .swiftformatignore 4 | .spi.yml 5 | .swift-format 6 | .github/* 7 | *.md 8 | **/*.md 9 | CONTRIBUTORS.txt 10 | LICENSE.txt 11 | NOTICE.txt 12 | Package.swift 13 | Package@swift-*.swift 14 | Package.resolved 15 | **/*.docc/* 16 | **/.gitignore 17 | **/Package.swift 18 | **/Package.resolved 19 | **/docker-compose*.yaml 20 | **/docker/* 21 | **/.dockerignore 22 | **/Dockerfile 23 | **/Makefile 24 | **/*.html 25 | **/*-template.yml 26 | **/*.xcworkspace/* 27 | **/*.xcodeproj/* 28 | **/*.xcassets/* 29 | **/*.appiconset/* 30 | **/ResourcePackaging/hello.txt 31 | .mailmap 32 | .swiftformat 33 | *.yaml 34 | *.yml 35 | **/.npmignore 36 | **/*.json 37 | **/*.txt -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Tomer Doron 2 | Tomer Doron 3 | Tomer Doron 4 | Fabian Fett 5 | Fabian Fett -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - documentation_targets: [AWSLambdaRuntime] 5 | -------------------------------------------------------------------------------- /.swift-format: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 1, 3 | "indentation" : { 4 | "spaces" : 4 5 | }, 6 | "tabWidth" : 4, 7 | "fileScopedDeclarationPrivacy" : { 8 | "accessLevel" : "private" 9 | }, 10 | "spacesAroundRangeFormationOperators" : false, 11 | "indentConditionalCompilationBlocks" : false, 12 | "indentSwitchCaseLabels" : false, 13 | "lineBreakAroundMultilineExpressionChainComponents" : false, 14 | "lineBreakBeforeControlFlowKeywords" : false, 15 | "lineBreakBeforeEachArgument" : true, 16 | "lineBreakBeforeEachGenericRequirement" : true, 17 | "lineLength" : 120, 18 | "maximumBlankLines" : 1, 19 | "respectsExistingLineBreaks" : true, 20 | "prioritizeKeepingFunctionOutputTogether" : true, 21 | "rules" : { 22 | "AllPublicDeclarationsHaveDocumentation" : false, 23 | "AlwaysUseLiteralForEmptyCollectionInit" : false, 24 | "AlwaysUseLowerCamelCase" : false, 25 | "AmbiguousTrailingClosureOverload" : true, 26 | "BeginDocumentationCommentWithOneLineSummary" : false, 27 | "DoNotUseSemicolons" : true, 28 | "DontRepeatTypeInStaticProperties" : true, 29 | "FileScopedDeclarationPrivacy" : true, 30 | "FullyIndirectEnum" : true, 31 | "GroupNumericLiterals" : true, 32 | "IdentifiersMustBeASCII" : true, 33 | "NeverForceUnwrap" : false, 34 | "NeverUseForceTry" : false, 35 | "NeverUseImplicitlyUnwrappedOptionals" : false, 36 | "NoAccessLevelOnExtensionDeclaration" : true, 37 | "NoAssignmentInExpressions" : true, 38 | "NoBlockComments" : true, 39 | "NoCasesWithOnlyFallthrough" : true, 40 | "NoEmptyTrailingClosureParentheses" : true, 41 | "NoLabelsInCasePatterns" : true, 42 | "NoLeadingUnderscores" : false, 43 | "NoParensAroundConditions" : true, 44 | "NoVoidReturnOnFunctionSignature" : true, 45 | "OmitExplicitReturns" : true, 46 | "OneCasePerLine" : true, 47 | "OneVariableDeclarationPerLine" : true, 48 | "OnlyOneTrailingClosureArgument" : true, 49 | "OrderedImports" : true, 50 | "ReplaceForEachWithForLoop" : true, 51 | "ReturnVoidInsteadOfEmptyTuple" : true, 52 | "UseEarlyExits" : false, 53 | "UseExplicitNilCheckInConditions" : false, 54 | "UseLetInEveryBoundCaseVariable" : false, 55 | "UseShorthandTypeNames" : true, 56 | "UseSingleLinePropertyGetter" : false, 57 | "UseSynthesizedInitializer" : false, 58 | "UseTripleSlashForDocumentationComments" : true, 59 | "UseWhereClausesInForLoops" : false, 60 | "ValidateDocumentationComments" : false 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The code of conduct for this project can be found at https://swift.org/code-of-conduct. 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Legal 2 | 3 | By submitting a pull request, you represent that you have the right to license 4 | your contribution to Apple and the community, and agree by submitting the patch 5 | that your contributions are licensed under the Apache 2.0 license (see 6 | `LICENSE.txt`). 7 | 8 | 9 | ## How to submit a bug report 10 | 11 | Please ensure to specify the following: 12 | 13 | * SwiftAWSLambdaRuntime commit hash 14 | * Contextual information (e.g. what you were trying to achieve with SwiftAWSLambdaRuntime) 15 | * Simplest possible steps to reproduce 16 | * More complex the steps are, lower the priority will be. 17 | * A pull request with failing test case is preferred, but it's just fine to paste the test case into the issue description. 18 | * Anything that might be relevant in your opinion, such as: 19 | * Swift version or the output of `swift --version` 20 | * OS version and the output of `uname -a` 21 | * Network configuration 22 | 23 | 24 | ### Example 25 | 26 | ``` 27 | SwiftAWSLambdaRuntime commit hash: 22ec043dc9d24bb011b47ece4f9ee97ee5be2757 28 | 29 | Context: 30 | While load testing my Lambda written with SwiftAWSLambdaRuntime, I noticed 31 | that one file descriptor is leaked per request. 32 | 33 | Steps to reproduce: 34 | 1. ... 35 | 2. ... 36 | 3. ... 37 | 4. ... 38 | 39 | $ swift --version 40 | Swift version 4.0.2 (swift-4.0.2-RELEASE) 41 | Target: x86_64-unknown-linux-gnu 42 | 43 | Operating system: Ubuntu Linux 16.04 64-bit 44 | 45 | $ uname -a 46 | Linux beefy.machine 4.4.0-101-generic #124-Ubuntu SMP Fri Nov 10 18:29:59 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux 47 | 48 | My system has IPv6 disabled. 49 | ``` 50 | 51 | ## Writing a Patch 52 | 53 | A good SwiftAWSLambdaRuntime patch is: 54 | 55 | 1. Concise, and contains as few changes as needed to achieve the end result. 56 | 2. Tested, ensuring that any tests provided failed before the patch and pass after it. 57 | 3. Documented, adding API documentation as needed to cover new functions and properties. 58 | 4. Accompanied by a great commit message, using our commit message template. 59 | 60 | ### Commit Message Template 61 | 62 | We require that your commit messages match our template. The easiest way to do that is to get git to help you by explicitly using the template. To do that, `cd` to the root of our repository and run: 63 | 64 | git config commit.template dev/git.commit.template 65 | 66 | ## How to contribute your work 67 | 68 | Please open a pull request at https://github.com/swift-server/swift-aws-lambda-runtime. Make sure the CI passes, and then wait for code review. 69 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | For the purpose of tracking copyright, this is the list of individuals and 2 | organizations who have contributed source code to SwiftAWSLambdaRuntime. 3 | 4 | For employees of an organization/company where the copyright of work done 5 | by employees of that company is held by the company itself, only the company 6 | needs to be listed here. 7 | 8 | ## COPYRIGHT HOLDERS 9 | 10 | - Apple Inc. (all contributors with '@apple.com') 11 | 12 | ### Contributors 13 | 14 | - Adam Fowler 15 | - Andrea Scuderi 16 | - Brendan Kirchner 17 | - Bryan Bartow 18 | - Bryan Moffatt 19 | - Christoph Walcher 20 | - Colton Schlosser 21 | - Eneko Alonso 22 | - Fabian Fett 23 | - George Barnett 24 | - Johannes Weiss 25 | - Max Desiatov 26 | - Norman Maurer 27 | - Ro-M 28 | - Tomer Doron 29 | - Zhibin Cai 30 | - pmarrufo 31 | - tachyonics 32 | 33 | **Updating this list** 34 | 35 | Please do not edit this file manually. It is generated using `./scripts/generate_contributors_list.sh`. If a name is misspelled or appearing multiple times: add an entry in `./.mailmap` 36 | -------------------------------------------------------------------------------- /Examples/APIGateway+LambdaAuthorizer/.gitignore: -------------------------------------------------------------------------------- 1 | samconfig.toml 2 | Makefile 3 | -------------------------------------------------------------------------------- /Examples/APIGateway+LambdaAuthorizer/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "APIGatewayLambda", targets: ["APIGatewayLambda"]), 13 | .executable(name: "AuthorizerLambda", targets: ["AuthorizerLambda"]), 14 | ], 15 | dependencies: [ 16 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 17 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 18 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"), 19 | ], 20 | targets: [ 21 | .executableTarget( 22 | name: "APIGatewayLambda", 23 | dependencies: [ 24 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 25 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 26 | ] 27 | ), 28 | .executableTarget( 29 | name: "AuthorizerLambda", 30 | dependencies: [ 31 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 32 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 33 | ] 34 | ), 35 | ] 36 | ) 37 | 38 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 39 | localDepsPath != "", 40 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 41 | v.isDirectory == true 42 | { 43 | // when we use the local runtime as deps, let's remove the dependency added above 44 | let indexToRemove = package.dependencies.firstIndex { dependency in 45 | if case .sourceControl( 46 | name: _, 47 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 48 | requirement: _ 49 | ) = dependency.kind { 50 | return true 51 | } 52 | return false 53 | } 54 | if let indexToRemove { 55 | package.dependencies.remove(at: indexToRemove) 56 | } 57 | 58 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 59 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 60 | package.dependencies += [ 61 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /Examples/APIGateway+LambdaAuthorizer/Sources/APIGatewayLambda/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | 18 | let runtime = LambdaRuntime { 19 | (event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response in 20 | 21 | var header = HTTPHeaders() 22 | context.logger.debug("HTTP API Message received") 23 | 24 | header["content-type"] = "application/json" 25 | 26 | // echo the request in the response 27 | return try APIGatewayV2Response(statusCode: .ok, headers: header, encodableBody: event) 28 | } 29 | 30 | try await runtime.run() 31 | -------------------------------------------------------------------------------- /Examples/APIGateway+LambdaAuthorizer/Sources/AuthorizerLambda/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | 18 | // 19 | // This is an example of a policy authorizer that always authorizes the request. 20 | // The policy authorizer returns an IAM policy document that defines what the Lambda function caller can do and optional context key-value pairs 21 | // 22 | // This code is shown for the example only and is not used in this demo. 23 | // This code doesn't perform any type of token validation. It should be used as a reference only. 24 | let policyAuthorizerHandler: 25 | (APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws -> APIGatewayLambdaAuthorizerPolicyResponse = { 26 | (request: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in 27 | 28 | context.logger.debug("+++ Policy Authorizer called +++") 29 | 30 | // typically, this function will check the validity of the incoming token received in the request 31 | 32 | // then it creates and returns a response 33 | return APIGatewayLambdaAuthorizerPolicyResponse( 34 | principalId: "John Appleseed", 35 | 36 | // this policy allows the caller to invoke any API Gateway endpoint 37 | policyDocument: .init(statement: [ 38 | .init( 39 | action: "execute-api:Invoke", 40 | effect: .allow, 41 | resource: "*" 42 | ) 43 | 44 | ]), 45 | 46 | // this is additional context we want to return to the caller 47 | context: [ 48 | "abc1": "xyz1", 49 | "abc2": "xyz2", 50 | ] 51 | ) 52 | } 53 | 54 | // 55 | // This is an example of a simple authorizer that always authorizes the request. 56 | // A simple authorizer returns a yes/no decision and optional context key-value pairs 57 | // 58 | // This code doesn't perform any type of token validation. It should be used as a reference only. 59 | let simpleAuthorizerHandler: 60 | (APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws -> APIGatewayLambdaAuthorizerSimpleResponse = { 61 | (_: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in 62 | 63 | context.logger.debug("+++ Simple Authorizer called +++") 64 | 65 | // typically, this function will check the validity of the incoming token received in the request 66 | 67 | return APIGatewayLambdaAuthorizerSimpleResponse( 68 | // this is the authorization decision: yes or no 69 | isAuthorized: true, 70 | 71 | // this is additional context we want to return to the caller 72 | context: ["abc1": "xyz1"] 73 | ) 74 | } 75 | 76 | // create the runtime and start polling for new events. 77 | // in this demo we use the simple authorizer handler 78 | let runtime = LambdaRuntime(body: simpleAuthorizerHandler) 79 | try await runtime.run() 80 | -------------------------------------------------------------------------------- /Examples/APIGateway+LambdaAuthorizer/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: SAM Template for APIGateway Lambda Example 4 | 5 | Resources: 6 | # The API Gateway 7 | MyProtectedApi: 8 | Type: AWS::Serverless::HttpApi 9 | Properties: 10 | Auth: 11 | DefaultAuthorizer: MyLambdaRequestAuthorizer 12 | Authorizers: 13 | MyLambdaRequestAuthorizer: 14 | FunctionArn: !GetAtt AuthorizerLambda.Arn 15 | Identity: 16 | Headers: 17 | - Authorization 18 | AuthorizerPayloadFormatVersion: "2.0" 19 | EnableSimpleResponses: true 20 | 21 | # Give the API Gateway permissions to invoke the Lambda authorizer 22 | AuthorizerPermission: 23 | Type: AWS::Lambda::Permission 24 | Properties: 25 | Action: lambda:InvokeFunction 26 | FunctionName: !Ref AuthorizerLambda 27 | Principal: apigateway.amazonaws.com 28 | SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${MyProtectedApi}/* 29 | 30 | # Lambda business function 31 | APIGatewayLambda: 32 | Type: AWS::Serverless::Function 33 | Properties: 34 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip 35 | Timeout: 60 36 | Handler: swift.bootstrap # ignored by the Swift runtime 37 | Runtime: provided.al2 38 | MemorySize: 512 39 | Architectures: 40 | - arm64 41 | Environment: 42 | Variables: 43 | # by default, AWS Lambda runtime produces no log 44 | # use `LOG_LEVEL: debug` for for lifecycle and event handling information 45 | # use `LOG_LEVEL: trace` for detailed input event information 46 | LOG_LEVEL: debug 47 | Events: 48 | HttpApiEvent: 49 | Type: HttpApi 50 | Properties: 51 | ApiId: !Ref MyProtectedApi 52 | Path: /demo 53 | Method: ANY 54 | 55 | # Lambda authorizer function 56 | AuthorizerLambda: 57 | Type: AWS::Serverless::Function 58 | Properties: 59 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/AuthorizerLambda/AuthorizerLambda.zip 60 | Timeout: 29 # max 29 seconds for Lambda authorizers 61 | Handler: swift.bootstrap # ignored by the Swift runtime 62 | Runtime: provided.al2 63 | MemorySize: 512 64 | Architectures: 65 | - arm64 66 | Environment: 67 | Variables: 68 | # by default, AWS Lambda runtime produces no log 69 | # use `LOG_LEVEL: debug` for for lifecycle and event handling information 70 | # use `LOG_LEVEL: trace` for detailed input event information 71 | LOG_LEVEL: debug 72 | 73 | Outputs: 74 | # print API Gateway endpoint 75 | APIGatewayEndpoint: 76 | Description: API Gateway endpoint URI 77 | Value: !Sub "https://${MyProtectedApi}.execute-api.${AWS::Region}.amazonaws.com/demo" 78 | -------------------------------------------------------------------------------- /Examples/APIGateway/.gitignore: -------------------------------------------------------------------------------- 1 | samconfig.toml 2 | Makefile 3 | -------------------------------------------------------------------------------- /Examples/APIGateway/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "APIGatewayLambda", targets: ["APIGatewayLambda"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 17 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"), 18 | ], 19 | targets: [ 20 | .executableTarget( 21 | name: "APIGatewayLambda", 22 | dependencies: [ 23 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 24 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 25 | ], 26 | path: "Sources" 27 | ) 28 | ] 29 | ) 30 | 31 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 32 | localDepsPath != "", 33 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 34 | v.isDirectory == true 35 | { 36 | // when we use the local runtime as deps, let's remove the dependency added above 37 | let indexToRemove = package.dependencies.firstIndex { dependency in 38 | if case .sourceControl( 39 | name: _, 40 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 41 | requirement: _ 42 | ) = dependency.kind { 43 | return true 44 | } 45 | return false 46 | } 47 | if let indexToRemove { 48 | package.dependencies.remove(at: indexToRemove) 49 | } 50 | 51 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 52 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 53 | package.dependencies += [ 54 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /Examples/APIGateway/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | 18 | let runtime = LambdaRuntime { 19 | (event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response in 20 | 21 | var header = HTTPHeaders() 22 | context.logger.debug("HTTP API Message received") 23 | 24 | header["content-type"] = "application/json" 25 | 26 | // echo the request in the response 27 | return try APIGatewayV2Response(statusCode: .ok, headers: header, encodableBody: event) 28 | } 29 | 30 | try await runtime.run() 31 | -------------------------------------------------------------------------------- /Examples/APIGateway/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: SAM Template for APIGateway Lambda Example 4 | 5 | Resources: 6 | # Lambda function 7 | APIGatewayLambda: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip 11 | Timeout: 60 12 | Handler: swift.bootstrap # ignored by the Swift runtime 13 | Runtime: provided.al2 14 | MemorySize: 512 15 | Architectures: 16 | - arm64 17 | Environment: 18 | Variables: 19 | # by default, AWS Lambda runtime produces no log 20 | # use `LOG_LEVEL: debug` for for lifecycle and event handling information 21 | # use `LOG_LEVEL: trace` for detailed input event information 22 | LOG_LEVEL: debug 23 | Events: 24 | HttpApiEvent: 25 | Type: HttpApi 26 | 27 | Outputs: 28 | # print API Gateway endpoint 29 | APIGatewayEndpoint: 30 | Description: API Gateway endpoint UR" 31 | Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" 32 | -------------------------------------------------------------------------------- /Examples/BackgroundTasks/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /Examples/BackgroundTasks/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "BackgroundTasks", targets: ["BackgroundTasks"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 17 | ], 18 | targets: [ 19 | .executableTarget( 20 | name: "BackgroundTasks", 21 | dependencies: [ 22 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 23 | ], 24 | path: "Sources" 25 | ) 26 | ] 27 | ) 28 | 29 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 30 | localDepsPath != "", 31 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 32 | v.isDirectory == true 33 | { 34 | // when we use the local runtime as deps, let's remove the dependency added above 35 | let indexToRemove = package.dependencies.firstIndex { dependency in 36 | if case .sourceControl( 37 | name: _, 38 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 39 | requirement: _ 40 | ) = dependency.kind { 41 | return true 42 | } 43 | return false 44 | } 45 | if let indexToRemove { 46 | package.dependencies.remove(at: indexToRemove) 47 | } 48 | 49 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 50 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 51 | package.dependencies += [ 52 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /Examples/BackgroundTasks/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | 17 | #if canImport(FoundationEssentials) 18 | import FoundationEssentials 19 | #else 20 | import Foundation 21 | #endif 22 | 23 | struct BackgroundProcessingHandler: LambdaWithBackgroundProcessingHandler { 24 | struct Input: Decodable { 25 | let message: String 26 | } 27 | 28 | struct Greeting: Encodable { 29 | let echoedMessage: String 30 | } 31 | 32 | typealias Event = Input 33 | typealias Output = Greeting 34 | 35 | func handle( 36 | _ event: Event, 37 | outputWriter: some LambdaResponseWriter, 38 | context: LambdaContext 39 | ) async throws { 40 | // Return result to the Lambda control plane 41 | context.logger.debug("BackgroundProcessingHandler - message received") 42 | try await outputWriter.write(Greeting(echoedMessage: event.message)) 43 | 44 | // Perform some background work, e.g: 45 | context.logger.debug("BackgroundProcessingHandler - response sent. Performing background tasks.") 46 | try await Task.sleep(for: .seconds(10)) 47 | 48 | // Exit the function. All asynchronous work has been executed before exiting the scope of this function. 49 | // Follows structured concurrency principles. 50 | context.logger.debug("BackgroundProcessingHandler - Background tasks completed. Returning") 51 | return 52 | } 53 | } 54 | 55 | let adapter = LambdaCodableAdapter(handler: BackgroundProcessingHandler()) 56 | let runtime = LambdaRuntime.init(handler: adapter) 57 | try await runtime.run() 58 | -------------------------------------------------------------------------------- /Examples/CDK/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "APIGatewayLambda", targets: ["APIGatewayLambda"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 17 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"), 18 | ], 19 | targets: [ 20 | .executableTarget( 21 | name: "APIGatewayLambda", 22 | dependencies: [ 23 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 24 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 25 | ], 26 | path: "Sources" 27 | ) 28 | ] 29 | ) 30 | 31 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 32 | localDepsPath != "", 33 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 34 | v.isDirectory == true 35 | { 36 | // when we use the local runtime as deps, let's remove the dependency added above 37 | let indexToRemove = package.dependencies.firstIndex { dependency in 38 | if case .sourceControl( 39 | name: _, 40 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 41 | requirement: _ 42 | ) = dependency.kind { 43 | return true 44 | } 45 | return false 46 | } 47 | if let indexToRemove { 48 | package.dependencies.remove(at: indexToRemove) 49 | } 50 | 51 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 52 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 53 | package.dependencies += [ 54 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /Examples/CDK/README.md: -------------------------------------------------------------------------------- 1 | # API Gateway and Cloud Development Kit 2 | 3 | This is a simple example of an AWS Lambda function invoked through an Amazon API Gateway and deployed with the Cloud Development Kit (CDK). 4 | 5 | ## Code 6 | 7 | The Lambda function takes all HTTP headers it receives as input and returns them as output. See the [API Gateway example](Examples/APIGateway/README.md) for a complete description of the code. 8 | 9 | ## Build & Package 10 | 11 | To build the package, type the following commands. 12 | 13 | ```bash 14 | swift build 15 | swift package archive --allow-network-connections docker 16 | ``` 17 | 18 | If there is no error, there is a ZIP file ready to deploy. 19 | The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip` 20 | 21 | ## Deploy 22 | 23 | >[NOTE] 24 | >Before deploying the infrastructure, you need to have NodeJS and the AWS CDK installed and configured. 25 | >For more information, see the [AWS CDK documentation](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html). 26 | 27 | To deploy the infrastructure, type the following commands. 28 | 29 | ```sh 30 | # Change to the infra directory 31 | cd infra 32 | 33 | # Install the dependencies (only before the first deployment) 34 | npm install 35 | 36 | cdk deploy 37 | 38 | ✨ Synthesis time: 2.88s 39 | ... redacted for brevity ... 40 | Do you wish to deploy these changes (y/n)? y 41 | ... redacted for brevity ... 42 | ✅ LambdaApiStack 43 | 44 | ✨ Deployment time: 42.96s 45 | 46 | Outputs: 47 | LambdaApiStack.ApiUrl = https://tyqnjcawh0.execute-api.eu-central-1.amazonaws.com/ 48 | Stack ARN: 49 | arn:aws:cloudformation:eu-central-1:401955065246:stack/LambdaApiStack/e0054390-be05-11ef-9504-065628de4b89 50 | 51 | ✨ Total time: 45.84s 52 | ``` 53 | 54 | ## Invoke your Lambda function 55 | 56 | To invoke the Lambda function, use this `curl` command line. 57 | 58 | ```bash 59 | curl https://tyqnjcawh0.execute-api.eu-central-1.amazonaws.com 60 | ``` 61 | 62 | Be sure to replace the URL with the API Gateway endpoint returned in the previous step. 63 | 64 | This should print a JSON similar to 65 | 66 | ```bash 67 | {"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"} 68 | ``` 69 | 70 | If you have `jq` installed, you can use it to pretty print the output. 71 | 72 | ```bash 73 | curl -s https://tyqnjcawh0.execute-api.eu-central-1.amazonaws.com | jq 74 | { 75 | "version": "2.0", 76 | "rawPath": "/", 77 | "requestContext": { 78 | "domainPrefix": "a5q74es3k2", 79 | "stage": "$default", 80 | "timeEpoch": 1727726558220, 81 | "http": { 82 | "protocol": "HTTP/1.1", 83 | "method": "GET", 84 | "userAgent": "curl/8.7.1", 85 | "path": "/", 86 | "sourceIp": "81.0.0.43" 87 | }, 88 | "apiId": "a5q74es3k2", 89 | "accountId": "012345678901", 90 | "requestId": "e72KxgsRoAMEMSA=", 91 | "domainName": "a5q74es3k2.execute-api.us-east-1.amazonaws.com", 92 | "time": "30/Sep/2024:20:02:38 +0000" 93 | }, 94 | "rawQueryString": "", 95 | "routeKey": "$default", 96 | "headers": { 97 | "x-forwarded-for": "81.0.0.43", 98 | "user-agent": "curl/8.7.1", 99 | "host": "a5q74es3k2.execute-api.us-east-1.amazonaws.com", 100 | "accept": "*/*", 101 | "x-amzn-trace-id": "Root=1-66fb03de-07533930192eaf5f540db0cb", 102 | "content-length": "0", 103 | "x-forwarded-proto": "https", 104 | "x-forwarded-port": "443" 105 | }, 106 | "isBase64Encoded": false 107 | } 108 | ``` 109 | 110 | ## Undeploy 111 | 112 | When done testing, you can delete the infrastructure with this command. 113 | 114 | ```bash 115 | cdk destroy 116 | 117 | Are you sure you want to delete: LambdaApiStack (y/n)? y 118 | LambdaApiStack: destroying... [1/1] 119 | ... redacted for brevity ... 120 | ✅ LambdaApiStack: destroyed 121 | ``` -------------------------------------------------------------------------------- /Examples/CDK/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | 18 | #if canImport(FoundationEssentials) 19 | import FoundationEssentials 20 | #else 21 | import Foundation 22 | #endif 23 | 24 | let encoder = JSONEncoder() 25 | let runtime = LambdaRuntime { 26 | (event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response in 27 | 28 | var header = HTTPHeaders() 29 | context.logger.debug("HTTP API Message received") 30 | 31 | header["content-type"] = "application/json" 32 | 33 | // echo the request in the response 34 | let data = try encoder.encode(event) 35 | let response = String(decoding: data, as: Unicode.UTF8.self) 36 | 37 | return APIGatewayV2Response(statusCode: .ok, headers: header, body: response) 38 | } 39 | 40 | try await runtime.run() 41 | -------------------------------------------------------------------------------- /Examples/CDK/infra/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | 10 | -------------------------------------------------------------------------------- /Examples/CDK/infra/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /Examples/CDK/infra/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your CDK TypeScript project 2 | 3 | This is a blank project for CDK development with TypeScript. 4 | 5 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 6 | 7 | ## Useful commands 8 | 9 | * `npm run build` compile typescript to js 10 | * `npm run watch` watch for changes and compile 11 | * `npm run test` perform the jest unit tests 12 | * `npx cdk deploy` deploy this stack to your default AWS account/region 13 | * `npx cdk diff` compare deployed stack with current state 14 | * `npx cdk synth` emits the synthesized CloudFormation template 15 | -------------------------------------------------------------------------------- /Examples/CDK/infra/bin/deploy.ts: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import * as cdk from 'aws-cdk-lib'; 16 | import { LambdaApiStack } from '../lib/lambda-api-project-stack'; 17 | 18 | const app = new cdk.App(); 19 | new LambdaApiStack(app, 'LambdaApiStack'); 20 | -------------------------------------------------------------------------------- /Examples/CDK/infra/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/deploy.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 38 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 39 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 40 | "@aws-cdk/aws-route53-patters:useCertificate": true, 41 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 42 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 43 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 44 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 45 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 46 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 47 | "@aws-cdk/aws-redshift:columnId": true, 48 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 49 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 50 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 51 | "@aws-cdk/aws-kms:aliasNameRef": true, 52 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 53 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 54 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 55 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 56 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 57 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 58 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 59 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 60 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 61 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 62 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 63 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, 64 | "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, 65 | "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, 66 | "@aws-cdk/aws-eks:nodegroupNameAttribute": true, 67 | "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, 68 | "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, 69 | "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, 70 | "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, 71 | "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, 72 | "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, 73 | "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, 74 | "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, 75 | "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, 76 | "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, 77 | "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, 78 | "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true, 79 | "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Examples/CDK/infra/lib/lambda-api-project-stack.ts: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import * as cdk from 'aws-cdk-lib'; 16 | import * as lambda from 'aws-cdk-lib/aws-lambda'; 17 | import * as apigateway from 'aws-cdk-lib/aws-apigatewayv2'; 18 | import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations'; 19 | 20 | export class LambdaApiStack extends cdk.Stack { 21 | constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 22 | super(scope, id, props); 23 | 24 | // Create the Lambda function 25 | const lambdaFunction = new lambda.Function(this, 'SwiftLambdaFunction', { 26 | runtime: lambda.Runtime.PROVIDED_AL2, 27 | architecture: lambda.Architecture.ARM_64, 28 | handler: 'bootstrap', 29 | code: lambda.Code.fromAsset('../.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip'), 30 | memorySize: 512, 31 | timeout: cdk.Duration.seconds(30), 32 | environment: { 33 | LOG_LEVEL: 'debug', 34 | }, 35 | }); 36 | 37 | // Create the integration 38 | const integration = new HttpLambdaIntegration( 39 | 'LambdaIntegration', 40 | lambdaFunction 41 | ); 42 | 43 | // Create HTTP API with the integration 44 | const httpApi = new apigateway.HttpApi(this, 'HttpApi', { 45 | defaultIntegration: integration, 46 | }); 47 | 48 | // Output the API URL 49 | new cdk.CfnOutput(this, 'ApiUrl', { 50 | value: httpApi.url ?? 'Something went wrong', 51 | }); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Examples/CDK/infra/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deploy", 3 | "version": "0.1.0", 4 | "bin": { 5 | "deploy": "bin/deploy.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "cdk": "cdk" 11 | }, 12 | "devDependencies": { 13 | "@types/jest": "^29.5.14", 14 | "@types/node": "22.13.10", 15 | "aws-cdk": "2.1003.0", 16 | "ts-node": "^10.9.2", 17 | "typescript": "~5.8.2" 18 | }, 19 | "dependencies": { 20 | "aws-cdk-lib": "^2.189.1", 21 | "constructs": "^10.4.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/CDK/infra/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /Examples/HelloJSON/.gitignore: -------------------------------------------------------------------------------- 1 | response.json 2 | samconfig.toml 3 | template.yaml 4 | Makefile 5 | -------------------------------------------------------------------------------- /Examples/HelloJSON/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.1 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "HelloJSON", targets: ["HelloJSON"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package( 17 | url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 18 | branch: "ff-package-traits", 19 | traits: [ 20 | .trait(name: "FoundationJSONSupport") 21 | ] 22 | ) 23 | ], 24 | targets: [ 25 | .executableTarget( 26 | name: "HelloJSON", 27 | dependencies: [ 28 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 29 | ] 30 | ) 31 | ] 32 | ) 33 | 34 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 35 | localDepsPath != "", 36 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 37 | v.isDirectory == true 38 | { 39 | // when we use the local runtime as deps, let's remove the dependency added above 40 | let indexToRemove = package.dependencies.firstIndex { dependency in 41 | if case .sourceControl( 42 | name: _, 43 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 44 | requirement: _ 45 | ) = dependency.kind { 46 | return true 47 | } 48 | return false 49 | } 50 | if let indexToRemove { 51 | package.dependencies.remove(at: indexToRemove) 52 | } 53 | 54 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 55 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 56 | package.dependencies += [ 57 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /Examples/HelloJSON/README.md: -------------------------------------------------------------------------------- 1 | # Hello JSON 2 | 3 | This is a simple example of an AWS Lambda function that takes a JSON structure as an input parameter and returns a JSON structure as a response. 4 | 5 | The runtime takes care of decoding the input and encoding the output. 6 | 7 | ## Code 8 | 9 | The code defines `HelloRequest` and `HelloResponse` data structures to represent the input and output payloads. These structures are typically shared with a client project, such as an iOS application. 10 | 11 | The code creates a `LambdaRuntime` struct. In it's simplest form, the initializer takes a function as an argument. The function is the handler that will be invoked when an event triggers the Lambda function. 12 | 13 | The handler is `(event: HelloRequest, context: LambdaContext)`. The function takes two arguments: 14 | - the event argument is a `HelloRequest`. It is the parameter passed when invoking the function. 15 | - the context argument is a `Lambda Context`. It is a description of the runtime context. 16 | 17 | The function return value will be encoded to a `HelloResponse` as your Lambda function response. 18 | 19 | ## Build & Package 20 | 21 | To build & archive the package, type the following commands. 22 | 23 | ```bash 24 | swift package archive --allow-network-connections docker 25 | ``` 26 | 27 | If there is no error, there is a ZIP file ready to deploy. 28 | The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HelloJSON/HelloJSON.zip` 29 | 30 | ## Deploy 31 | 32 | Here is how to deploy using the `aws` command line. 33 | 34 | ```bash 35 | # Replace with your AWS Account ID 36 | AWS_ACCOUNT_ID=012345678901 37 | 38 | aws lambda create-function \ 39 | --function-name HelloJSON \ 40 | --zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/HelloJSON/HelloJSON.zip \ 41 | --runtime provided.al2 \ 42 | --handler provided \ 43 | --architectures arm64 \ 44 | --role arn:aws:iam::${AWS_ACCOUNT_ID}:role/lambda_basic_execution 45 | ``` 46 | 47 | 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`. 48 | 49 | Be sure to define the `AWS_ACCOUNT_ID` environment variable with your actual AWS account ID (for example: 012345678901). 50 | 51 | ## Invoke your Lambda function 52 | 53 | To invoke the Lambda function, use this `aws` command line. 54 | 55 | ```bash 56 | aws lambda invoke \ 57 | --function-name HelloJSON \ 58 | --payload $(echo '{ "name" : "Seb", "age" : 50 }' | base64) \ 59 | out.txt && cat out.txt && rm out.txt 60 | ``` 61 | 62 | Note that the payload is expected to be a valid JSON string. 63 | 64 | This should output the following result. 65 | 66 | ``` 67 | { 68 | "StatusCode": 200, 69 | "ExecutedVersion": "$LATEST" 70 | } 71 | {"greetings":"Hello Seb. You look younger than your age."} 72 | ``` 73 | 74 | ## Undeploy 75 | 76 | When done testing, you can delete the Lambda function with this command. 77 | 78 | ```bash 79 | aws lambda delete-function --function-name HelloJSON 80 | ``` -------------------------------------------------------------------------------- /Examples/HelloJSON/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | 17 | // in this example we are receiving and responding with JSON structures 18 | 19 | // the data structure to represent the input parameter 20 | struct HelloRequest: Decodable { 21 | let name: String 22 | let age: Int 23 | } 24 | 25 | // the data structure to represent the output response 26 | struct HelloResponse: Encodable { 27 | let greetings: String 28 | } 29 | 30 | // the Lambda runtime 31 | let runtime = LambdaRuntime { 32 | (event: HelloRequest, context: LambdaContext) in 33 | 34 | HelloResponse( 35 | greetings: "Hello \(event.name). You look \(event.age > 30 ? "younger" : "older") than your age." 36 | ) 37 | } 38 | 39 | // start the loop 40 | try await runtime.run() 41 | -------------------------------------------------------------------------------- /Examples/HelloWorld/.gitignore: -------------------------------------------------------------------------------- 1 | response.json 2 | samconfig.toml 3 | template.yaml 4 | Makefile 5 | -------------------------------------------------------------------------------- /Examples/HelloWorld/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "MyLambda", targets: ["MyLambda"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 17 | ], 18 | targets: [ 19 | .executableTarget( 20 | name: "MyLambda", 21 | dependencies: [ 22 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 23 | ], 24 | path: "Sources" 25 | ) 26 | ] 27 | ) 28 | 29 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 30 | localDepsPath != "", 31 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 32 | v.isDirectory == true 33 | { 34 | // when we use the local runtime as deps, let's remove the dependency added above 35 | let indexToRemove = package.dependencies.firstIndex { dependency in 36 | if case .sourceControl( 37 | name: _, 38 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 39 | requirement: _ 40 | ) = dependency.kind { 41 | return true 42 | } 43 | return false 44 | } 45 | if let indexToRemove { 46 | package.dependencies.remove(at: indexToRemove) 47 | } 48 | 49 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 50 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 51 | package.dependencies += [ 52 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /Examples/HelloWorld/README.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | 3 | This is a simple example of an AWS Lambda function that takes a `String` as input parameter and returns a `String` as response. 4 | 5 | ## Code 6 | 7 | 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. 8 | 9 | The handler is `(event: String, context: LambdaContext)`. The function takes two arguments: 10 | - the event argument is a `String`. It is the parameter passed when invoking the function. 11 | - the context argument is a `Lambda Context`. It is a description of the runtime context. 12 | 13 | The function return value will be encoded as your Lambda function response. 14 | 15 | ## Test locally 16 | 17 | You can test your function locally before deploying it to AWS Lambda. 18 | 19 | To start the local function, type the following commands: 20 | 21 | ```bash 22 | swift run 23 | ``` 24 | 25 | It will compile your code and start the local server. You know the local server is ready to accept connections when you see this message. 26 | 27 | ```txt 28 | Building for debugging... 29 | [1/1] Write swift-version--644A47CB88185983.txt 30 | Build of product 'MyLambda' complete! (0.31s) 31 | 2025-01-29T12:44:48+0100 info LocalServer : host="127.0.0.1" port=7000 [AWSLambdaRuntime] Server started and listening 32 | ``` 33 | 34 | Then, from another Terminal, send your payload with `curl`. Note that the payload must be a valid JSON string. In the case of this function that accepts a simple String, it means the String must be wrapped in between double quotes. 35 | 36 | ```bash 37 | curl -d '"seb"' http://127.0.0.1:7000/invoke 38 | "Hello seb" 39 | ``` 40 | 41 | > [!IMPORTANT] 42 | > The local server is only available in `DEBUG` mode. It will not start with `swift -c release run`. 43 | 44 | ## Build & Package 45 | 46 | To build & archive the package, type the following commands. 47 | 48 | ```bash 49 | swift build 50 | swift package archive --allow-network-connections docker 51 | ``` 52 | 53 | If there is no error, there is a ZIP file ready to deploy. 54 | The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/MyLambda/MyLambda.zip` 55 | 56 | ## Deploy 57 | 58 | Here is how to deploy using the `aws` command line. 59 | 60 | ```bash 61 | aws lambda create-function \ 62 | --function-name MyLambda \ 63 | --zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/MyLambda/MyLambda.zip \ 64 | --runtime provided.al2 \ 65 | --handler provided \ 66 | --architectures arm64 \ 67 | --role arn:aws:iam:::role/lambda_basic_execution 68 | ``` 69 | 70 | 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`. 71 | 72 | Be sure to replace with your actual AWS account ID (for example: 012345678901). 73 | 74 | ## Invoke your Lambda function 75 | 76 | To invoke the Lambda function, use this `aws` command line. 77 | 78 | ```bash 79 | aws lambda invoke \ 80 | --function-name MyLambda \ 81 | --payload $(echo \"Seb\" | base64) \ 82 | out.txt && cat out.txt && rm out.txt 83 | ``` 84 | 85 | Note that the payload is expected to be a valid JSON string, hence the surroundings quotes (`"`). 86 | 87 | This should output the following result. 88 | 89 | ``` 90 | { 91 | "StatusCode": 200, 92 | "ExecutedVersion": "$LATEST" 93 | } 94 | "Hello Seb" 95 | ``` 96 | 97 | ## Undeploy 98 | 99 | When done testing, you can delete the Lambda function with this command. 100 | 101 | ```bash 102 | aws lambda delete-function --function-name MyLambda 103 | ``` -------------------------------------------------------------------------------- /Examples/HelloWorld/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | 17 | // in this example we are receiving and responding with strings 18 | 19 | let runtime = LambdaRuntime { 20 | (event: String, context: LambdaContext) in 21 | "Hello \(event)" 22 | } 23 | 24 | try await runtime.run() 25 | -------------------------------------------------------------------------------- /Examples/ResourcesPackaging/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /Examples/ResourcesPackaging/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | // needed for CI to test the local version of the library 7 | import struct Foundation.URL 8 | 9 | let package = Package( 10 | name: "ResourcesPackaging", 11 | platforms: [.macOS(.v15)], 12 | products: [ 13 | .executable(name: "MyLambda", targets: ["MyLambda"]) 14 | ], 15 | dependencies: [ 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 17 | ], 18 | targets: [ 19 | .executableTarget( 20 | name: "MyLambda", 21 | dependencies: [ 22 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 23 | ], 24 | path: ".", 25 | resources: [ 26 | .process("hello.txt") 27 | ] 28 | ) 29 | ] 30 | ) 31 | 32 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 33 | localDepsPath != "", 34 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 35 | v.isDirectory == true 36 | { 37 | // when we use the local runtime as deps, let's remove the dependency added above 38 | let indexToRemove = package.dependencies.firstIndex { dependency in 39 | if case .sourceControl( 40 | name: _, 41 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 42 | requirement: _ 43 | ) = dependency.kind { 44 | return true 45 | } 46 | return false 47 | } 48 | if let indexToRemove { 49 | package.dependencies.remove(at: indexToRemove) 50 | } 51 | 52 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 53 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 54 | package.dependencies += [ 55 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /Examples/ResourcesPackaging/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | import Foundation 17 | 18 | let runtime = LambdaRuntime { 19 | (event: String, context: LambdaContext) in 20 | guard let fileURL = Bundle.module.url(forResource: "hello", withExtension: "txt") else { 21 | fatalError("no file url") 22 | } 23 | return try String(contentsOf: fileURL, encoding: .utf8) 24 | } 25 | 26 | try await runtime.run() 27 | -------------------------------------------------------------------------------- /Examples/ResourcesPackaging/hello.txt: -------------------------------------------------------------------------------- 1 | Hello World 2 | -------------------------------------------------------------------------------- /Examples/S3EventNotifier/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /.index-build 4 | /Packages 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/configuration/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /Examples/S3EventNotifier/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | import PackageDescription 3 | 4 | // needed for CI to test the local version of the library 5 | import struct Foundation.URL 6 | 7 | let package = Package( 8 | name: "S3EventNotifier", 9 | platforms: [.macOS(.v15)], 10 | dependencies: [ 11 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 12 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events", branch: "main"), 13 | ], 14 | targets: [ 15 | .executableTarget( 16 | name: "S3EventNotifier", 17 | dependencies: [ 18 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 19 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 20 | ] 21 | ) 22 | ] 23 | ) 24 | 25 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 26 | localDepsPath != "", 27 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 28 | v.isDirectory == true 29 | { 30 | // when we use the local runtime as deps, let's remove the dependency added above 31 | let indexToRemove = package.dependencies.firstIndex { dependency in 32 | if case .sourceControl( 33 | name: _, 34 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 35 | requirement: _ 36 | ) = dependency.kind { 37 | return true 38 | } 39 | return false 40 | } 41 | if let indexToRemove { 42 | package.dependencies.remove(at: indexToRemove) 43 | } 44 | 45 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 46 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 47 | package.dependencies += [ 48 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /Examples/S3EventNotifier/README.md: -------------------------------------------------------------------------------- 1 | # S3 Event Notifier 2 | 3 | This example demonstrates how to write a Lambda that is invoked by an event originating from Amazon S3, such as a new object being uploaded to a bucket. 4 | 5 | ## Code 6 | 7 | In this example the Lambda function receives an `S3Event` object defined in the `AWSLambdaEvents` library as input object. The `S3Event` object contains all the information about the S3 event that triggered the function, but what we are interested in is the bucket name and the object key, which are inside of a notification `Record`. The object contains an array of records, however since the Lambda function is triggered by a single event, we can safely assume that there is only one record in the array: the first one. Inside of this record, we can find the bucket name and the object key: 8 | 9 | ```swift 10 | guard let s3NotificationRecord = event.records.first else { 11 | throw LambdaError.noNotificationRecord 12 | } 13 | 14 | let bucket = s3NotificationRecord.s3.bucket.name 15 | let key = s3NotificationRecord.s3.object.key.replacingOccurrences(of: "+", with: " ") 16 | ``` 17 | 18 | The key is URL encoded, so we replace the `+` with a space. 19 | 20 | ## Build & Package 21 | 22 | To build & archive the package you can use the following commands: 23 | 24 | ```bash 25 | swift build 26 | swift package archive --allow-network-connections docker 27 | ``` 28 | 29 | If there are no errors, a ZIP file should be ready to deploy, located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/S3EventNotifier/S3EventNotifier.zip`. 30 | 31 | ## Deploy 32 | 33 | > [!IMPORTANT] 34 | > The Lambda function and the S3 bucket must be located in the same AWS Region. In the code below, we use `eu-west-1` (Ireland). 35 | 36 | To deploy the Lambda function, you can use the `aws` command line: 37 | 38 | ```bash 39 | REGION=eu-west-1 40 | aws lambda create-function \ 41 | --region "${REGION}" \ 42 | --function-name S3EventNotifier \ 43 | --zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/S3EventNotifier/S3EventNotifier.zip \ 44 | --runtime provided.al2 \ 45 | --handler provided \ 46 | --architectures arm64 \ 47 | --role arn:aws:iam:::role/lambda_basic_execution 48 | ``` 49 | 50 | 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`. 51 | 52 | Be sure to define `REGION` with the region where you want to deploy your Lambda function and replace `` with your actual AWS account ID (for example: 012345678901). 53 | 54 | Besides deploying the Lambda function you also need to create the S3 bucket and configure it to send events to the Lambda function. You can do this using the following commands: 55 | 56 | ```bash 57 | REGION=eu-west-1 58 | 59 | aws s3api create-bucket \ 60 | --region "${REGION}" \ 61 | --bucket my-test-bucket \ 62 | --create-bucket-configuration LocationConstraint="${REGION}" 63 | 64 | aws lambda add-permission \ 65 | --region "${REGION}" \ 66 | --function-name S3EventNotifier \ 67 | --statement-id S3InvokeFunction \ 68 | --action lambda:InvokeFunction \ 69 | --principal s3.amazonaws.com \ 70 | --source-arn arn:aws:s3:::my-test-bucket 71 | 72 | aws s3api put-bucket-notification-configuration \ 73 | --region "${REGION}" \ 74 | --bucket my-test-bucket \ 75 | --notification-configuration '{ 76 | "LambdaFunctionConfigurations": [{ 77 | "LambdaFunctionArn": "arn:aws:lambda:${REGION}::function:S3EventNotifier", 78 | "Events": ["s3:ObjectCreated:*"] 79 | }] 80 | }' 81 | 82 | touch testfile.txt && aws s3 cp testfile.txt s3://my-test-bucket/ 83 | ``` 84 | 85 | This will: 86 | - create a bucket named `my-test-bucket` in the `$REGION` region; 87 | - add a permission to the Lambda function to be invoked by Amazon S3; 88 | - configure the bucket to send `s3:ObjectCreated:*` events to the Lambda function named `S3EventNotifier`; 89 | - upload a file named `testfile.txt` to the bucket. 90 | 91 | Replace `my-test-bucket` with your bucket name (bucket names are unique globaly and this one is already taken). Also replace `REGION` environment variable with the AWS Region where you deployed the Lambda function and `` with your actual AWS account ID. 92 | 93 | > [!IMPORTANT] 94 | > The Lambda function and the S3 bucket must be located in the same AWS Region. Adjust the code above according to your closest AWS Region. -------------------------------------------------------------------------------- /Examples/S3EventNotifier/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | import Foundation 18 | 19 | let runtime = LambdaRuntime { (event: S3Event, context: LambdaContext) async throws in 20 | guard let s3NotificationRecord = event.records.first else { 21 | context.logger.error("No S3 notification record found in the event") 22 | return 23 | } 24 | 25 | let bucket = s3NotificationRecord.s3.bucket.name 26 | let key = s3NotificationRecord.s3.object.key.replacingOccurrences(of: "+", with: " ") 27 | 28 | context.logger.info("Received notification from S3 bucket '\(bucket)' for object with key '\(key)'") 29 | 30 | // Here you could, for example, notify an API or a messaging service 31 | } 32 | 33 | try await runtime.run() 34 | -------------------------------------------------------------------------------- /Examples/S3_AWSSDK/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .aws-sam/ 3 | .build 4 | samtemplate.toml 5 | */build/* 6 | /.build 7 | /Packages 8 | xcuserdata/ 9 | DerivedData/ 10 | .swiftpm/configuration/registries.json 11 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 12 | .netrc -------------------------------------------------------------------------------- /Examples/S3_AWSSDK/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "AWSSDKExample", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "AWSSDKExample", targets: ["AWSSDKExample"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 17 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events", from: "1.0.0"), 18 | .package(url: "https://github.com/awslabs/aws-sdk-swift", from: "1.0.0"), 19 | ], 20 | targets: [ 21 | .executableTarget( 22 | name: "AWSSDKExample", 23 | dependencies: [ 24 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 25 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 26 | .product(name: "AWSS3", package: "aws-sdk-swift"), 27 | ] 28 | ) 29 | ] 30 | ) 31 | 32 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 33 | localDepsPath != "", 34 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 35 | v.isDirectory == true 36 | { 37 | // when we use the local runtime as deps, let's remove the dependency added above 38 | let indexToRemove = package.dependencies.firstIndex { dependency in 39 | if case .sourceControl( 40 | name: _, 41 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 42 | requirement: _ 43 | ) = dependency.kind { 44 | return true 45 | } 46 | return false 47 | } 48 | if let indexToRemove { 49 | package.dependencies.remove(at: indexToRemove) 50 | } 51 | 52 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 53 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 54 | package.dependencies += [ 55 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /Examples/S3_AWSSDK/README.md: -------------------------------------------------------------------------------- 1 | # List Amazon S3 Buckets with the AWS SDK for Swift 2 | 3 | This is a simple example of an AWS Lambda function that uses the [AWS SDK for Swift](https://github.com/awslabs/aws-sdk-swift) to read data from Amazon S3. 4 | 5 | ## Code 6 | 7 | The Lambda function reads all bucket names from your AWS account and returns them as a String. 8 | 9 | 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. 10 | 11 | The handler is `(event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response`. The function takes two arguments: 12 | - 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. 13 | - the context argument is a `Lambda Context`. It is a description of the runtime context. 14 | 15 | The function must return a `APIGatewayV2Response`. 16 | 17 | `APIGatewayV2Request` and `APIGatewayV2Response` are defined in the [Swift AWS Lambda Events](https://github.com/swift-server/swift-aws-lambda-events) library. 18 | 19 | The handler creates an S3 client and `ListBucketsInput` object. It passes the input object to the client and receives an output response. 20 | It then extracts the list of bucket names from the output and creates a `\n`-separated list of names, as a `String` 21 | 22 | ## Build & Package 23 | 24 | To build the package, type the following commands. 25 | 26 | ```bash 27 | swift build 28 | swift package archive --allow-network-connections docker 29 | ``` 30 | 31 | If there is no error, there is a ZIP file ready to deploy. 32 | The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/AWSSDKExample/AWSSDKExample.zip` 33 | 34 | ## Deploy 35 | 36 | The deployment must include the Lambda function and an 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. 37 | 38 | **Prerequisites** : Install the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) 39 | 40 | The example directory contains a file named `template.yaml` that describes the deployment. 41 | 42 | To actually deploy your Lambda function and create the infrastructure, type the following `sam` command. 43 | 44 | ```bash 45 | sam deploy \ 46 | --resolve-s3 \ 47 | --template-file template.yaml \ 48 | --stack-name AWSSDKExample \ 49 | --capabilities CAPABILITY_IAM 50 | ``` 51 | 52 | At the end of the deployment, the script lists the API Gateway endpoint. 53 | The output is similar to this one. 54 | 55 | ``` 56 | ----------------------------------------------------------------------------------------------------------------------------- 57 | Outputs 58 | ----------------------------------------------------------------------------------------------------------------------------- 59 | Key APIGatewayEndpoint 60 | Description API Gateway endpoint URL" 61 | Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com 62 | ----------------------------------------------------------------------------------------------------------------------------- 63 | ``` 64 | 65 | ## Invoke your Lambda function 66 | 67 | To invoke the Lambda function, use this `curl` command line. 68 | 69 | ```bash 70 | curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com 71 | ``` 72 | 73 | Be sure to replace the URL with the API Gateway endpoint returned in the previous step. 74 | 75 | This should print text similar to 76 | 77 | ```bash 78 | my_bucket_1 79 | my_bucket_2 80 | ... 81 | ``` 82 | 83 | ## Delete the infrastructure 84 | 85 | When done testing, you can delete the infrastructure with this command. 86 | 87 | ```bash 88 | sam delete 89 | ``` -------------------------------------------------------------------------------- /Examples/S3_AWSSDK/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | @preconcurrency import AWSS3 18 | 19 | let client = try await S3Client() 20 | 21 | let runtime = LambdaRuntime { 22 | (event: APIGatewayV2Request, context: LambdaContext) async throws -> APIGatewayV2Response in 23 | 24 | var response: APIGatewayV2Response 25 | do { 26 | // read the list of buckets 27 | context.logger.debug("Reading list of buckets") 28 | let output = try await client.listBuckets(input: ListBucketsInput()) 29 | let bucketList = output.buckets?.compactMap { $0.name } 30 | response = APIGatewayV2Response(statusCode: .ok, body: bucketList?.joined(separator: "\n")) 31 | } catch { 32 | context.logger.error("\(error)") 33 | response = APIGatewayV2Response(statusCode: .internalServerError, body: "[ERROR] \(error)") 34 | } 35 | return response 36 | } 37 | 38 | try await runtime.run() 39 | -------------------------------------------------------------------------------- /Examples/S3_AWSSDK/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: SAM Template for AWS SDK Example 4 | 5 | Resources: 6 | # Lambda function 7 | AWSSDKExample: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/AWSSDKExample/AWSSDKExample.zip 11 | Timeout: 60 12 | Handler: swift.bootstrap # ignored by the Swift runtime 13 | Runtime: provided.al2 14 | MemorySize: 512 15 | Architectures: 16 | - arm64 17 | Environment: 18 | Variables: 19 | # by default, AWS Lambda runtime produces no log 20 | # use `LOG_LEVEL: debug` for for lifecycle and event handling information 21 | # use `LOG_LEVEL: trace` for detailed input event information 22 | LOG_LEVEL: debug 23 | 24 | # Handles all methods of the REST API 25 | Events: 26 | Api: 27 | Type: HttpApi 28 | 29 | # Add an IAM policy to this function. 30 | # It grants the function permissions to read the list of buckets in your account. 31 | Policies: 32 | - Statement: 33 | - Sid: ListAllS3BucketsInYourAccount 34 | Effect: Allow 35 | Action: 36 | - s3:ListAllMyBuckets 37 | Resource: '*' 38 | 39 | # print API endpoint 40 | Outputs: 41 | SwiftAPIEndpoint: 42 | Description: "API Gateway endpoint URL for your application" 43 | Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" 44 | -------------------------------------------------------------------------------- /Examples/S3_Soto/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .aws-sam/ 3 | .build 4 | samtemplate.toml 5 | */build/* 6 | /.build 7 | /Packages 8 | xcuserdata/ 9 | DerivedData/ 10 | .swiftpm/configuration/registries.json 11 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 12 | .netrc -------------------------------------------------------------------------------- /Examples/S3_Soto/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "SotoExample", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "SotoExample", targets: ["SotoExample"]) 13 | ], 14 | dependencies: [ 15 | .package(url: "https://github.com/soto-project/soto.git", from: "7.0.0"), 16 | 17 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 18 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 19 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events", from: "1.0.0"), 20 | ], 21 | targets: [ 22 | .executableTarget( 23 | name: "SotoExample", 24 | dependencies: [ 25 | .product(name: "SotoS3", package: "soto"), 26 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 27 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 28 | ] 29 | ) 30 | ] 31 | ) 32 | 33 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 34 | localDepsPath != "", 35 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 36 | v.isDirectory == true 37 | { 38 | // when we use the local runtime as deps, let's remove the dependency added above 39 | let indexToRemove = package.dependencies.firstIndex { dependency in 40 | if case .sourceControl( 41 | name: _, 42 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 43 | requirement: _ 44 | ) = dependency.kind { 45 | return true 46 | } 47 | return false 48 | } 49 | if let indexToRemove { 50 | package.dependencies.remove(at: indexToRemove) 51 | } 52 | 53 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 54 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 55 | package.dependencies += [ 56 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /Examples/S3_Soto/README.md: -------------------------------------------------------------------------------- 1 | # List Amazon S3 Buckets with Soto 2 | 3 | This is a simple example of an AWS Lambda function that uses the [Soto SDK for AWS](https://github.com/soto-project/soto) to read data from Amazon S3. 4 | 5 | ## Code 6 | 7 | The Lambda function reads all bucket names from your AWS account and returns them as a String. 8 | 9 | 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. 10 | 11 | The handler is `(event: APIGatewayV2Request, context: LambdaContext) -> APIGatewayV2Response`. The function takes two arguments: 12 | - 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. 13 | - the context argument is a `Lambda Context`. It is a description of the runtime context. 14 | 15 | The function must return a `APIGatewayV2Response`. 16 | 17 | `APIGatewayV2Request` and `APIGatewayV2Response` are defined in the [Swift AWS Lambda Events](https://github.com/swift-server/swift-aws-lambda-events) library. 18 | 19 | The handler creates two clients : an AWS client that manages the communication with AWS API and and the S3 client that expose the S3 API. Then, the handler calls `listBuckets()` on the S3 client and receives an output response. 20 | Finally, the handler extracts the list of bucket names from the output to create a `\n`-separated list of names, as a `String`. 21 | 22 | ## Build & Package 23 | 24 | To build the package, type the following command. 25 | 26 | ```bash 27 | swift build 28 | swift package archive --allow-network-connections docker 29 | ``` 30 | 31 | If there is no error, there is a ZIP file ready to deploy. 32 | The ZIP file is located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/SotoExample/SotoExample.zip` 33 | 34 | ## Deploy 35 | 36 | The deployment must include the Lambda function and an 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. 37 | 38 | **Prerequisites** : Install the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) 39 | 40 | The example directory contains a file named `template.yaml` that describes the deployment. 41 | 42 | To actually deploy your Lambda function and create the infrastructure, type the following `sam` command. 43 | 44 | ```bash 45 | sam deploy \ 46 | --resolve-s3 \ 47 | --template-file template.yaml \ 48 | --stack-name SotoExample \ 49 | --capabilities CAPABILITY_IAM 50 | ``` 51 | 52 | At the end of the deployment, the script lists the API Gateway endpoint. 53 | The output is similar to this one. 54 | 55 | ``` 56 | ----------------------------------------------------------------------------------------------------------------------------- 57 | Outputs 58 | ----------------------------------------------------------------------------------------------------------------------------- 59 | Key APIGatewayEndpoint 60 | Description API Gateway endpoint URL" 61 | Value https://a5q74es3k2.execute-api.us-east-1.amazonaws.com 62 | ----------------------------------------------------------------------------------------------------------------------------- 63 | ``` 64 | 65 | ## Invoke your Lambda function 66 | 67 | To invoke the Lambda function, use this `curl` command line. 68 | 69 | ```bash 70 | curl https://a5q74es3k2.execute-api.us-east-1.amazonaws.com 71 | ``` 72 | 73 | Be sure to replace the URL with the API Gateway endpoint returned in the previous step. 74 | 75 | This should print text similar to 76 | 77 | ```bash 78 | my_bucket_1 79 | my_bucket_2 80 | ... 81 | ``` 82 | 83 | ## Delete the infrastructure 84 | 85 | When done testing, you can delete the infrastructure with this command. 86 | 87 | ```bash 88 | sam delete 89 | ``` -------------------------------------------------------------------------------- /Examples/S3_Soto/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | import SotoS3 18 | 19 | let client = AWSClient() 20 | let s3 = S3(client: client, region: .useast1) 21 | 22 | func handler(event: APIGatewayV2Request, context: LambdaContext) async throws -> APIGatewayV2Response { 23 | 24 | var response: APIGatewayV2Response 25 | do { 26 | context.logger.debug("Reading list of buckets") 27 | 28 | // read the list of buckets 29 | let bucketResponse = try await s3.listBuckets() 30 | let bucketList = bucketResponse.buckets?.compactMap { $0.name } 31 | response = APIGatewayV2Response(statusCode: .ok, body: bucketList?.joined(separator: "\n")) 32 | } catch { 33 | context.logger.error("\(error)") 34 | response = APIGatewayV2Response(statusCode: .internalServerError, body: "[ERROR] \(error)") 35 | } 36 | return response 37 | } 38 | 39 | let runtime = LambdaRuntime.init(body: handler) 40 | 41 | try await runtime.run() 42 | try await client.shutdown() 43 | -------------------------------------------------------------------------------- /Examples/S3_Soto/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: SAM Template for AWS SDK Example 4 | 5 | Resources: 6 | # Lambda function 7 | SotoExample: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/SotoExample/SotoExample.zip 11 | Timeout: 60 12 | Handler: swift.bootstrap # ignored by the Swift runtime 13 | Runtime: provided.al2 14 | MemorySize: 512 15 | Architectures: 16 | - arm64 17 | Environment: 18 | Variables: 19 | # by default, AWS Lambda runtime produces no log 20 | # use `LOG_LEVEL: debug` for for lifecycle and event handling information 21 | # use `LOG_LEVEL: trace` for detailed input event information 22 | LOG_LEVEL: debug 23 | 24 | # Handles all methods of the REST API 25 | Events: 26 | Api: 27 | Type: HttpApi 28 | 29 | # Add an IAM policy to this function. 30 | # It grants the function permissions to read the list of buckets in your account. 31 | Policies: 32 | - Statement: 33 | - Sid: ListAllS3BucketsInYourAccount 34 | Effect: Allow 35 | Action: 36 | - s3:ListAllMyBuckets 37 | Resource: '*' 38 | 39 | # print API endpoint 40 | Outputs: 41 | SwiftAPIEndpoint: 42 | Description: "API Gateway endpoint URL for your application" 43 | Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" 44 | -------------------------------------------------------------------------------- /Examples/Streaming/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /Examples/Streaming/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "StreamingNumbers", targets: ["StreamingNumbers"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 17 | ], 18 | targets: [ 19 | .executableTarget( 20 | name: "StreamingNumbers", 21 | dependencies: [ 22 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 23 | ], 24 | path: "Sources" 25 | ) 26 | ] 27 | ) 28 | 29 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 30 | localDepsPath != "", 31 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 32 | v.isDirectory == true 33 | { 34 | // when we use the local runtime as deps, let's remove the dependency added above 35 | let indexToRemove = package.dependencies.firstIndex { dependency in 36 | if case .sourceControl( 37 | name: _, 38 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 39 | requirement: _ 40 | ) = dependency.kind { 41 | return true 42 | } 43 | return false 44 | } 45 | if let indexToRemove { 46 | package.dependencies.remove(at: indexToRemove) 47 | } 48 | 49 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 50 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 51 | package.dependencies += [ 52 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /Examples/Streaming/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | import NIOCore 17 | 18 | struct SendNumbersWithPause: StreamingLambdaHandler { 19 | func handle( 20 | _ event: ByteBuffer, 21 | responseWriter: some LambdaResponseStreamWriter, 22 | context: LambdaContext 23 | ) async throws { 24 | for i in 1...10 { 25 | // Send partial data 26 | try await responseWriter.write(ByteBuffer(string: "\(i)\n")) 27 | // Perform some long asynchronous work 28 | try await Task.sleep(for: .milliseconds(1000)) 29 | } 30 | // All data has been sent. Close off the response stream. 31 | try await responseWriter.finish() 32 | } 33 | } 34 | 35 | let runtime = LambdaRuntime.init(handler: SendNumbersWithPause()) 36 | try await runtime.run() 37 | -------------------------------------------------------------------------------- /Examples/Streaming/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: SAM Template for Streaming Example 4 | 5 | Resources: 6 | # Lambda function 7 | StreamingNumbers: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/StreamingNumbers/StreamingNumbers.zip 11 | Timeout: 15 12 | Handler: swift.bootstrap # ignored by the Swift runtime 13 | Runtime: provided.al2 14 | MemorySize: 128 15 | Architectures: 16 | - arm64 17 | FunctionUrlConfig: 18 | AuthType: AWS_IAM 19 | InvokeMode: RESPONSE_STREAM 20 | 21 | Outputs: 22 | # print Lambda function URL 23 | LambdaURL: 24 | Description: Lambda URL 25 | Value: !GetAtt StreamingNumbersUrl.FunctionUrl 26 | -------------------------------------------------------------------------------- /Examples/Testing/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | // needed for CI to test the local version of the library 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "swift-aws-lambda-runtime-example", 10 | platforms: [.macOS(.v15)], 11 | products: [ 12 | .executable(name: "APIGatewayLambda", targets: ["APIGatewayLambda"]) 13 | ], 14 | dependencies: [ 15 | // during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below 16 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"), 17 | .package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"), 18 | ], 19 | targets: [ 20 | .executableTarget( 21 | name: "APIGatewayLambda", 22 | dependencies: [ 23 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), 24 | .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), 25 | ], 26 | path: "Sources" 27 | ), 28 | .testTarget( 29 | name: "LambdaFunctionTests", 30 | dependencies: ["APIGatewayLambda"], 31 | path: "Tests", 32 | resources: [ 33 | .process("event.json") 34 | ] 35 | ), 36 | ] 37 | ) 38 | 39 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 40 | localDepsPath != "", 41 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 42 | v.isDirectory == true 43 | { 44 | // when we use the local runtime as deps, let's remove the dependency added above 45 | let indexToRemove = package.dependencies.firstIndex { dependency in 46 | if case .sourceControl( 47 | name: _, 48 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 49 | requirement: _ 50 | ) = dependency.kind { 51 | return true 52 | } 53 | return false 54 | } 55 | if let indexToRemove { 56 | package.dependencies.remove(at: indexToRemove) 57 | } 58 | 59 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 60 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 61 | package.dependencies += [ 62 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /Examples/Testing/Sources/Business.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | extension String { 16 | /// Returns a new string with the first character capitalized and the remaining characters in lowercase. 17 | /// 18 | /// This method capitalizes the first character of the string and converts the remaining characters to lowercase. 19 | /// It is useful for formatting strings where only the first character should be uppercase. 20 | /// 21 | /// - Returns: A new string with the first character capitalized and the remaining characters in lowercase. 22 | /// 23 | /// - Example: 24 | /// ``` 25 | /// let example = "hello world" 26 | /// print(example.uppercasedFirst()) // Prints "Hello world" 27 | /// ``` 28 | func uppercasedFirst() -> String { 29 | let firstCharacter = prefix(1).capitalized 30 | let remainingCharacters = dropFirst().lowercased() 31 | return firstCharacter + remainingCharacters 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Examples/Testing/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | 18 | #if canImport(FoundationEssentials) 19 | import FoundationEssentials 20 | #else 21 | import Foundation 22 | #endif 23 | 24 | public struct MyHandler: Sendable { 25 | 26 | public func handler(event: APIGatewayV2Request, context: LambdaContext) async throws -> APIGatewayV2Response { 27 | context.logger.debug("HTTP API Message received") 28 | context.logger.trace("Event: \(event)") 29 | 30 | var header = HTTPHeaders() 31 | header["content-type"] = "application/json" 32 | 33 | // API Gateway sends text or URL encoded data as a Base64 encoded string 34 | if let base64EncodedString = event.body, 35 | let decodedData = Data(base64Encoded: base64EncodedString), 36 | let decodedString = String(data: decodedData, encoding: .utf8) 37 | { 38 | 39 | // call our business code to process the payload and return a response 40 | return APIGatewayV2Response(statusCode: .ok, headers: header, body: decodedString.uppercasedFirst()) 41 | } else { 42 | return APIGatewayV2Response(statusCode: .badRequest) 43 | } 44 | } 45 | } 46 | 47 | let runtime = LambdaRuntime(body: MyHandler().handler) 48 | try await runtime.run() 49 | -------------------------------------------------------------------------------- /Examples/Testing/Tests/BusinessTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Testing 16 | 17 | @testable import APIGatewayLambda // to access the business code 18 | 19 | let valuesToTest: [(String, String)] = [ 20 | ("hello world", "Hello world"), // happy path 21 | ("", ""), // Empty string 22 | ("a", "A"), // Single character 23 | ("A", "A"), // Single uppercase character 24 | ("HELLO WORLD", "Hello world"), // All uppercase 25 | ("hello world", "Hello world"), // All lowercase 26 | ("hElLo WoRlD", "Hello world"), // Mixed case 27 | ("123abc", "123abc"), // Numeric string 28 | ("!@#abc", "!@#abc"), // Special characters 29 | ] 30 | 31 | @Suite("Business Tests") 32 | class BusinessTests { 33 | 34 | @Test("Uppercased First", arguments: valuesToTest) 35 | func uppercasedFirst(_ arg: (String, String)) { 36 | let input = arg.0 37 | let expectedOutput = arg.1 38 | #expect(input.uppercasedFirst() == expectedOutput) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Examples/Testing/Tests/HandlerTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaEvents 16 | import AWSLambdaRuntime 17 | import Logging 18 | import Testing 19 | 20 | @testable import APIGatewayLambda // to access the business code 21 | @testable import AWSLambdaRuntime // to access the LambdaContext 22 | 23 | #if canImport(FoundationEssentials) 24 | import FoundationEssentials 25 | #else 26 | import Foundation 27 | #endif 28 | 29 | @Suite("Handler Tests") 30 | public struct HandlerTest { 31 | 32 | @Test("Invoke handler") 33 | public func invokeHandler() async throws { 34 | 35 | // read event.json file 36 | let testBundle = Bundle.module 37 | guard let eventURL = testBundle.url(forResource: "event", withExtension: "json") else { 38 | Issue.record("event.json not found in test bundle") 39 | return 40 | } 41 | let eventData = try Data(contentsOf: eventURL) 42 | 43 | // decode the event 44 | let apiGatewayRequest = try JSONDecoder().decode(APIGatewayV2Request.self, from: eventData) 45 | 46 | // create a mock LambdaContext 47 | let lambdaContext = LambdaContext.__forTestsOnly( 48 | requestID: UUID().uuidString, 49 | traceID: UUID().uuidString, 50 | invokedFunctionARN: "arn:", 51 | timeout: .milliseconds(6000), 52 | logger: Logger(label: "fakeContext") 53 | ) 54 | 55 | // call the handler with the event and context 56 | let response = try await MyHandler().handler(event: apiGatewayRequest, context: lambdaContext) 57 | 58 | // assert the response 59 | #expect(response.statusCode == .ok) 60 | #expect(response.body == "Hello world of swift lambda!") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Examples/Testing/Tests/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "rawPath": "/", 4 | "body": "aGVsbG8gd29ybGQgb2YgU1dJRlQgTEFNQkRBIQ==", 5 | "requestContext": { 6 | "domainPrefix": "a5q74es3k2", 7 | "stage": "$default", 8 | "timeEpoch": 1727726558220, 9 | "http": { 10 | "protocol": "HTTP/1.1", 11 | "method": "GET", 12 | "userAgent": "curl/8.7.1", 13 | "path": "/", 14 | "sourceIp": "81.0.0.43" 15 | }, 16 | "apiId": "a5q74es3k2", 17 | "accountId": "012345678901", 18 | "requestId": "e72KxgsRoAMEMSA=", 19 | "domainName": "a5q74es3k2.execute-api.us-east-1.amazonaws.com", 20 | "time": "30/Sep/2024:20:02:38 +0000" 21 | }, 22 | "rawQueryString": "", 23 | "routeKey": "$default", 24 | "headers": { 25 | "x-forwarded-for": "81.0.0.43", 26 | "user-agent": "curl/8.7.1", 27 | "host": "a5q74es3k2.execute-api.us-east-1.amazonaws.com", 28 | "accept": "*/*", 29 | "x-amzn-trace-id": "Root=1-66fb03de-07533930192eaf5f540db0cb", 30 | "content-length": "0", 31 | "x-forwarded-proto": "https", 32 | "x-forwarded-port": "443" 33 | }, 34 | "isBase64Encoded": false 35 | } 36 | -------------------------------------------------------------------------------- /Examples/Testing/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: SAM Template for APIGateway Lambda Example 4 | 5 | Resources: 6 | # Lambda function 7 | APIGatewayLambda: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/APIGatewayLambda/APIGatewayLambda.zip 11 | Timeout: 60 12 | Handler: swift.bootstrap # ignored by the Swift runtime 13 | Runtime: provided.al2 14 | MemorySize: 512 15 | Architectures: 16 | - arm64 17 | Environment: 18 | Variables: 19 | # by default, AWS Lambda runtime produces no log 20 | # use `LOG_LEVEL: debug` for for lifecycle and event handling information 21 | # use `LOG_LEVEL: trace` for detailed input event information 22 | LOG_LEVEL: trace 23 | Events: 24 | HttpApiEvent: 25 | Type: HttpApi 26 | 27 | Outputs: 28 | # print API Gateway endpoint 29 | APIGatewayEndpoint: 30 | Description: API Gateway endpoint UR" 31 | Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" 32 | -------------------------------------------------------------------------------- /Examples/Tutorial/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /Examples/Tutorial/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | import struct Foundation.URL 7 | 8 | let package = Package( 9 | name: "Palindrome", 10 | platforms: [.macOS(.v15)], 11 | dependencies: [ 12 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 13 | ], 14 | targets: [ 15 | // Targets are the basic building blocks of a package, defining a module or a test suite. 16 | // Targets can depend on other targets in this package and products from dependencies. 17 | .executableTarget( 18 | name: "Palindrome", 19 | dependencies: [ 20 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 21 | ] 22 | ) 23 | ] 24 | ) 25 | 26 | if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"], 27 | localDepsPath != "", 28 | let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]), 29 | v.isDirectory == true 30 | { 31 | // when we use the local runtime as deps, let's remove the dependency added above 32 | let indexToRemove = package.dependencies.firstIndex { dependency in 33 | if case .sourceControl( 34 | name: _, 35 | location: "https://github.com/swift-server/swift-aws-lambda-runtime.git", 36 | requirement: _ 37 | ) = dependency.kind { 38 | return true 39 | } 40 | return false 41 | } 42 | if let indexToRemove { 43 | package.dependencies.remove(at: indexToRemove) 44 | } 45 | 46 | // then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..) 47 | print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)") 48 | package.dependencies += [ 49 | .package(name: "swift-aws-lambda-runtime", path: localDepsPath) 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /Examples/Tutorial/Sources/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | 17 | // the data structure to represent the input parameter 18 | struct Request: Decodable { 19 | let text: String 20 | } 21 | 22 | // the data structure to represent the response parameter 23 | struct Response: Encodable { 24 | let text: String 25 | let isPalindrome: Bool 26 | let message: String 27 | } 28 | 29 | // the business function 30 | func isPalindrome(_ text: String) -> Bool { 31 | let cleanedText = text.lowercased().filter { $0.isLetter } 32 | return cleanedText == String(cleanedText.reversed()) 33 | } 34 | 35 | // the lambda handler function 36 | let runtime = LambdaRuntime { 37 | (event: Request, context: LambdaContext) -> Response in 38 | 39 | let result = isPalindrome(event.text) 40 | return Response( 41 | text: event.text, 42 | isPalindrome: result, 43 | message: "Your text is \(result ? "a" : "not a") palindrome" 44 | ) 45 | } 46 | 47 | // start the runtime 48 | try await runtime.run() 49 | -------------------------------------------------------------------------------- /Examples/_MyFirstFunction/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /Examples/_MyFirstFunction/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftAWSLambdaRuntime open source project 5 | ## 6 | ## Copyright (c) 2017-2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | echo "This script deletes the Lambda function and the IAM role created in the previous step and deletes the project files." 17 | read -r -p "Are you you sure you want to delete everything that was created? [y/n] " continue 18 | if [[ ! $continue =~ ^[Yy]$ ]]; then 19 | echo "OK, try again later when you feel ready" 20 | exit 1 21 | fi 22 | 23 | echo "🚀 Deleting the Lambda function and the role" 24 | aws lambda delete-function --function-name MyLambda 25 | aws iam detach-role-policy \ 26 | --role-name lambda_basic_execution \ 27 | --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 28 | aws iam delete-role --role-name lambda_basic_execution 29 | 30 | echo "🚀 Deleting the project files" 31 | rm -rf .build 32 | rm -rf ./Sources 33 | rm trust-policy.json 34 | rm Package.swift Package.resolved 35 | 36 | echo "🎉 Done! Your project is cleaned up and ready for a fresh start." -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | 2 | The SwiftAWSLambdaRuntime Project 3 | ================================= 4 | 5 | Please visit the SwiftAWSLambdaRuntime web site for more information: 6 | 7 | * https://github.com/swift-server/swift-aws-lambda-runtime 8 | 9 | Copyright 2017-2021 The SwiftAWSLambdaRuntime Project 10 | 11 | The SwiftAWSLambdaRuntime Project licenses this file to you under the Apache License, 12 | version 2.0 (the "License"); you may not use this file except in compliance 13 | with the License. You may obtain a copy of the License at: 14 | 15 | https://www.apache.org/licenses/LICENSE-2.0 16 | 17 | Unless required by applicable law or agreed to in writing, software 18 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 20 | License for the specific language governing permissions and limitations 21 | under the License. 22 | 23 | Also, please refer to each LICENSE.txt file, which is located in 24 | the 'license' directory of the distribution file, for the license terms of the 25 | components that this product depends on. 26 | 27 | ------------------------------------------------------------------------------- 28 | 29 | 30 | This product contains a derivation various code and scripts from SwiftNIO. 31 | 32 | * LICENSE (Apache License 2.0): 33 | * https://www.apache.org/licenses/LICENSE-2.0 34 | * HOMEPAGE: 35 | * https://github.com/apple/swift-nio 36 | 37 | --- 38 | 39 | This product contains a derivation of the swift-extras' 'swift-extras-uuid'. 40 | 41 | * LICENSE (MIT): 42 | * https://github.com/swift-extras/swift-extras-uuid/blob/main/LICENSE 43 | * HOMEPAGE: 44 | * https://github.com/swift-extras/swift-extras-uuid 45 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "swift-aws-lambda-runtime", 7 | platforms: [.macOS(.v15)], 8 | products: [ 9 | .library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]), 10 | // plugin to package the lambda, creating an archive that can be uploaded to AWS 11 | // requires Linux or at least macOS v15 12 | .plugin(name: "AWSLambdaPackager", targets: ["AWSLambdaPackager"]), 13 | ], 14 | traits: [ 15 | "FoundationJSONSupport", 16 | "ServiceLifecycleSupport", 17 | "LocalServerSupport", 18 | .default( 19 | enabledTraits: [ 20 | "FoundationJSONSupport", 21 | "ServiceLifecycleSupport", 22 | "LocalServerSupport", 23 | ] 24 | ), 25 | ], 26 | dependencies: [ 27 | .package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"), 28 | .package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"), 29 | .package(url: "https://github.com/apple/swift-collections.git", from: "1.1.4"), 30 | .package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.6.3"), 31 | ], 32 | targets: [ 33 | .target( 34 | name: "AWSLambdaRuntime", 35 | dependencies: [ 36 | .product(name: "NIOCore", package: "swift-nio"), 37 | .product(name: "DequeModule", package: "swift-collections"), 38 | .product(name: "Logging", package: "swift-log"), 39 | .product(name: "NIOHTTP1", package: "swift-nio"), 40 | .product(name: "NIOPosix", package: "swift-nio"), 41 | .product( 42 | name: "ServiceLifecycle", 43 | package: "swift-service-lifecycle", 44 | condition: .when(traits: ["ServiceLifecycleSupport"]) 45 | ), 46 | ] 47 | ), 48 | .plugin( 49 | name: "AWSLambdaPackager", 50 | capability: .command( 51 | intent: .custom( 52 | verb: "archive", 53 | description: 54 | "Archive the Lambda binary and prepare it for uploading to AWS. Requires docker on macOS or non Amazonlinux 2 distributions." 55 | ), 56 | permissions: [ 57 | .allowNetworkConnections( 58 | scope: .docker, 59 | reason: "This plugin uses Docker to create the AWS Lambda ZIP package." 60 | ) 61 | ] 62 | ) 63 | ), 64 | .testTarget( 65 | name: "AWSLambdaRuntimeTests", 66 | dependencies: [ 67 | .byName(name: "AWSLambdaRuntime"), 68 | .product(name: "NIOTestUtils", package: "swift-nio"), 69 | .product(name: "NIOFoundationCompat", package: "swift-nio"), 70 | ] 71 | ), 72 | // for perf testing 73 | .executableTarget( 74 | name: "MockServer", 75 | dependencies: [ 76 | .product(name: "Logging", package: "swift-log"), 77 | .product(name: "NIOHTTP1", package: "swift-nio"), 78 | .product(name: "NIOCore", package: "swift-nio"), 79 | .product(name: "NIOPosix", package: "swift-nio"), 80 | ] 81 | ), 82 | ] 83 | ) 84 | -------------------------------------------------------------------------------- /Package@swift-6.0.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "swift-aws-lambda-runtime", 7 | platforms: [.macOS(.v15)], 8 | products: [ 9 | .library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]), 10 | // plugin to package the lambda, creating an archive that can be uploaded to AWS 11 | // requires Linux or at least macOS v15 12 | .plugin(name: "AWSLambdaPackager", targets: ["AWSLambdaPackager"]), 13 | ], 14 | dependencies: [ 15 | .package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"), 16 | .package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"), 17 | .package(url: "https://github.com/apple/swift-collections.git", from: "1.1.4"), 18 | .package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.6.3"), 19 | ], 20 | targets: [ 21 | .target( 22 | name: "AWSLambdaRuntime", 23 | dependencies: [ 24 | .product(name: "NIOCore", package: "swift-nio"), 25 | .product(name: "DequeModule", package: "swift-collections"), 26 | .product(name: "Logging", package: "swift-log"), 27 | .product(name: "NIOHTTP1", package: "swift-nio"), 28 | .product(name: "NIOPosix", package: "swift-nio"), 29 | .product(name: "ServiceLifecycle", package: "swift-service-lifecycle"), 30 | ], 31 | swiftSettings: [ 32 | .define("FoundationJSONSupport"), 33 | .define("ServiceLifecycleSupport"), 34 | .define("LocalServerSupport"), 35 | ] 36 | ), 37 | .plugin( 38 | name: "AWSLambdaPackager", 39 | capability: .command( 40 | intent: .custom( 41 | verb: "archive", 42 | description: 43 | "Archive the Lambda binary and prepare it for uploading to AWS. Requires docker on macOS or non Amazonlinux 2 distributions." 44 | ), 45 | permissions: [ 46 | .allowNetworkConnections( 47 | scope: .docker, 48 | reason: "This plugin uses Docker to create the AWS Lambda ZIP package." 49 | ) 50 | ] 51 | ) 52 | ), 53 | .testTarget( 54 | name: "AWSLambdaRuntimeTests", 55 | dependencies: [ 56 | .byName(name: "AWSLambdaRuntime"), 57 | .product(name: "NIOTestUtils", package: "swift-nio"), 58 | .product(name: "NIOFoundationCompat", package: "swift-nio"), 59 | ] 60 | ), 61 | // for perf testing 62 | .executableTarget( 63 | name: "MockServer", 64 | dependencies: [ 65 | .product(name: "Logging", package: "swift-log"), 66 | .product(name: "NIOHTTP1", package: "swift-nio"), 67 | .product(name: "NIOCore", package: "swift-nio"), 68 | .product(name: "NIOPosix", package: "swift-nio"), 69 | ] 70 | ), 71 | ] 72 | ) 73 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | This document specifies the security process for the Swift AWS Lambda Runtime project. 4 | 5 | ## Disclosures 6 | 7 | ### Private Disclosure Process 8 | 9 | The Swift AWS Lambda Runtime maintainers ask that known and suspected vulnerabilities be 10 | privately and responsibly disclosed by emailing 11 | [sswg-security-reports@forums.swift.org](mailto:sswg-security-reports@forums.swift.org) 12 | with the all the required detail. 13 | **Do not file a public issue.** 14 | 15 | #### When to report a vulnerability 16 | 17 | * You think you have discovered a potential security vulnerability in Swift AWS Lambda Runtime. 18 | * You are unsure how a vulnerability affects Swift AWS Lambda Runtime. 19 | 20 | #### What happens next? 21 | 22 | * A member of the team will acknowledge receipt of the report within 3 23 | working days (United States). This may include a request for additional 24 | information about reproducing the vulnerability. 25 | * We will privately inform the Swift Server Work Group ([SSWG][sswg]) of the 26 | vulnerability within 10 days of the report as per their [security 27 | guidelines][sswg-security]. 28 | * Once we have identified a fix we may ask you to validate it. We aim to do this 29 | within 30 days. In some cases this may not be possible, for example when the 30 | vulnerability exists at the protocol level and the industry must coordinate on 31 | the disclosure process. 32 | * If a CVE number is required, one will be requested from [MITRE][mitre] 33 | providing you with full credit for the discovery. 34 | * We will decide on a planned release date and let you know when it is. 35 | * Prior to release, we will inform major dependents that a security-related 36 | patch is impending. 37 | * Once the fix has been released we will publish a security advisory on GitHub 38 | and in the Server → Security Updates category on the [Swift forums][swift-forums-sec]. 39 | 40 | [sswg]: https://github.com/swift-server/sswg 41 | [sswg-security]: https://github.com/swift-server/sswg/blob/main/security/README.md 42 | [swift-forums-sec]: https://forums.swift.org/c/server/security-updates/ 43 | [mitre]: https://cveform.mitre.org/ 44 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/ControlPlaneRequest.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2017-2021 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOCore 16 | import NIOHTTP1 17 | 18 | enum ControlPlaneRequest: Hashable { 19 | case next 20 | case invocationResponse(String, ByteBuffer?) 21 | case invocationError(String, ErrorResponse) 22 | case initializationError(ErrorResponse) 23 | } 24 | 25 | enum ControlPlaneResponse: Hashable { 26 | case next(InvocationMetadata, ByteBuffer) 27 | case accepted 28 | case error(ErrorResponse) 29 | } 30 | 31 | @usableFromInline 32 | package struct InvocationMetadata: Hashable, Sendable { 33 | @usableFromInline 34 | package let requestID: String 35 | @usableFromInline 36 | package let deadlineInMillisSinceEpoch: Int64 37 | @usableFromInline 38 | package let invokedFunctionARN: String 39 | @usableFromInline 40 | package let traceID: String 41 | @usableFromInline 42 | package let clientContext: String? 43 | @usableFromInline 44 | package let cognitoIdentity: String? 45 | 46 | package init(headers: HTTPHeaders) throws(LambdaRuntimeError) { 47 | guard let requestID = headers.first(name: AmazonHeaders.requestID), !requestID.isEmpty else { 48 | throw LambdaRuntimeError(code: .nextInvocationMissingHeaderRequestID) 49 | } 50 | 51 | guard let deadline = headers.first(name: AmazonHeaders.deadline), 52 | let unixTimeInMilliseconds = Int64(deadline) 53 | else { 54 | throw LambdaRuntimeError(code: .nextInvocationMissingHeaderDeadline) 55 | } 56 | 57 | guard let invokedFunctionARN = headers.first(name: AmazonHeaders.invokedFunctionARN) else { 58 | throw LambdaRuntimeError(code: .nextInvocationMissingHeaderInvokeFuctionARN) 59 | } 60 | 61 | self.requestID = requestID 62 | self.deadlineInMillisSinceEpoch = unixTimeInMilliseconds 63 | self.invokedFunctionARN = invokedFunctionARN 64 | self.traceID = 65 | headers.first(name: AmazonHeaders.traceID) ?? "Root=\(AmazonHeaders.generateXRayTraceID());Sampled=0" 66 | self.clientContext = headers["Lambda-Runtime-Client-Context"].first 67 | self.cognitoIdentity = headers["Lambda-Runtime-Cognito-Identity"].first 68 | } 69 | } 70 | 71 | struct ErrorResponse: Hashable, Codable { 72 | var errorType: String 73 | var errorMessage: String 74 | } 75 | 76 | extension ErrorResponse { 77 | func toJSONBytes() -> [UInt8] { 78 | var bytes = [UInt8]() 79 | bytes.append(UInt8(ascii: "{")) 80 | bytes.append(contentsOf: #""errorType":"#.utf8) 81 | self.errorType.encodeAsJSONString(into: &bytes) 82 | bytes.append(contentsOf: #","errorMessage":"#.utf8) 83 | self.errorMessage.encodeAsJSONString(into: &bytes) 84 | bytes.append(UInt8(ascii: "}")) 85 | return bytes 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Documentation.md: -------------------------------------------------------------------------------- 1 | # ``AWSLambdaRuntime`` 2 | 3 | An AWS Lambda runtime for the Swift programming language 4 | 5 | ## Overview 6 | 7 | Many modern systems have client components like iOS, macOS or watchOS applications as well as server components that those clients interact with. Serverless functions are often the easiest and most efficient way for client application developers to extend their applications into the cloud. 8 | 9 | Serverless functions are increasingly becoming a popular choice for running event-driven or otherwise ad-hoc compute tasks in the cloud. They power mission critical microservices and data intensive workloads. In many cases, serverless functions allow developers to more easily scale and control compute costs given their on-demand nature. 10 | 11 | When using serverless functions, attention must be given to resource utilization as it directly impacts the costs of the system. This is where Swift shines! With its low memory footprint, deterministic performance, and quick start time, Swift is a fantastic match for the serverless functions architecture. 12 | 13 | Combine this with Swift's developer friendliness, expressiveness, and emphasis on safety, and we have a solution that is great for developers at all skill levels, scalable, and cost effective. 14 | 15 | Swift AWS Lambda Runtime was designed to make building Lambda functions in Swift simple and safe. The library is an implementation of the [AWS Lambda Runtime API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html) and uses an embedded asynchronous HTTP client based on [SwiftNIO](https://github.com/apple/swift-nio) that is fine-tuned for performance in the AWS Lambda Runtime context. The library provides a multi-tier API that allows building a range of Lambda functions: from quick and simple closures to complex, performance-sensitive event handlers. 16 | 17 | ## Topics 18 | 19 | ### Essentials 20 | 21 | - 22 | - 23 | - 24 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/.shellcheckrc: -------------------------------------------------------------------------------- 1 | disable=all -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-01-01-package-init.sh: -------------------------------------------------------------------------------- 1 | # Create a project directory 2 | mkdir Palindrome && cd Palindrome 3 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-01-02-package-init.sh: -------------------------------------------------------------------------------- 1 | # Create a project directory 2 | mkdir Palindrome && cd Palindrome 3 | 4 | # create a skeleton project 5 | swift package init --type executable 6 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-01-03-package-init.sh: -------------------------------------------------------------------------------- 1 | # Create a project directory 2 | mkdir Palindrome && cd Palindrome 3 | 4 | # create a skeleton project 5 | swift package init --type executable 6 | 7 | # open Xcode in the current directory 8 | xed . 9 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-01-04-package-init.sh: -------------------------------------------------------------------------------- 1 | # Create a project directory 2 | mkdir Palindrome && cd Palindrome 3 | 4 | # create a skeleton project 5 | swift package init --type executable 6 | 7 | # open Xcode in the current directory 8 | xed . 9 | 10 | # alternatively, you may open VSCode 11 | code . -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-02-01-package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Palindrome" 8 | ) 9 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-02-02-package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Palindrome", 8 | platforms: [ 9 | .macOS(.v15) 10 | ] 11 | ) 12 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-02-03-package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Palindrome", 8 | platforms: [ 9 | .macOS(.v15) 10 | ], 11 | dependencies: [ 12 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 13 | ] 14 | ) 15 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-02-04-package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Palindrome", 8 | platforms: [ 9 | .macOS(.v15) 10 | ], 11 | products: [ 12 | .executable(name: "PalindromeLambda", targets: ["PalindromeLambda"]) 13 | ], 14 | dependencies: [ 15 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 16 | ] 17 | ) 18 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-02-05-package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Palindrome", 8 | platforms: [ 9 | .macOS(.v15) 10 | ], 11 | products: [ 12 | .executable(name: "PalindromeLambda", targets: ["PalindromeLambda"]) 13 | ], 14 | dependencies: [ 15 | .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main") 16 | ], 17 | targets: [ 18 | .executableTarget( 19 | name: "PalindromeLambda", 20 | dependencies: [ 21 | .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") 22 | ], 23 | path: "Sources" 24 | ) 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-01-main.swift: -------------------------------------------------------------------------------- 1 | // the data structure to represent the input parameter 2 | struct Request: Decodable { 3 | let text: String 4 | } 5 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-02-main.swift: -------------------------------------------------------------------------------- 1 | // the data structure to represent the input parameter 2 | struct Request: Decodable { 3 | let text: String 4 | } 5 | 6 | // the data structure to represent the response parameter 7 | struct Response: Encodable { 8 | let text: String 9 | let isPalindrome: Bool 10 | let message: String 11 | } 12 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-03-main.swift: -------------------------------------------------------------------------------- 1 | // the data structure to represent the input parameter 2 | struct Request: Decodable { 3 | let text: String 4 | } 5 | 6 | // the data structure to represent the response parameter 7 | struct Response: Encodable { 8 | let text: String 9 | let isPalindrome: Bool 10 | let message: String 11 | } 12 | 13 | // the business function 14 | func isPalindrome(_ text: String) -> Bool { 15 | let cleanedText = text.lowercased().filter { $0.isLetter } 16 | return cleanedText == String(cleanedText.reversed()) 17 | } 18 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-04-main.swift: -------------------------------------------------------------------------------- 1 | import AWSLambdaRuntime 2 | 3 | // the data structure to represent the input parameter 4 | struct Request: Decodable { 5 | let text: String 6 | } 7 | 8 | // the data structure to represent the response parameter 9 | struct Response: Encodable { 10 | let text: String 11 | let isPalindrome: Bool 12 | let message: String 13 | } 14 | 15 | // the business function 16 | func isPalindrome(_ text: String) -> Bool { 17 | let cleanedText = text.lowercased().filter { $0.isLetter } 18 | return cleanedText == String(cleanedText.reversed()) 19 | } 20 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-05-main.swift: -------------------------------------------------------------------------------- 1 | import AWSLambdaRuntime 2 | 3 | // the data structure to represent the input parameter 4 | struct Request: Decodable { 5 | let text: String 6 | } 7 | 8 | // the data structure to represent the response parameter 9 | struct Response: Encodable { 10 | let text: String 11 | let isPalindrome: Bool 12 | let message: String 13 | } 14 | 15 | // the business function 16 | func isPalindrome(_ text: String) -> Bool { 17 | let cleanedText = text.lowercased().filter { $0.isLetter } 18 | return cleanedText == String(cleanedText.reversed()) 19 | } 20 | 21 | // the lambda handler function 22 | let runtime = LambdaRuntime { 23 | (event: Request, context: LambdaContext) -> Response in 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-06-main.swift: -------------------------------------------------------------------------------- 1 | import AWSLambdaRuntime 2 | 3 | // the data structure to represent the input parameter 4 | struct Request: Decodable { 5 | let text: String 6 | } 7 | 8 | // the data structure to represent the response parameter 9 | struct Response: Encodable { 10 | let text: String 11 | let isPalindrome: Bool 12 | let message: String 13 | } 14 | 15 | // the business function 16 | func isPalindrome(_ text: String) -> Bool { 17 | let cleanedText = text.lowercased().filter { $0.isLetter } 18 | return cleanedText == String(cleanedText.reversed()) 19 | } 20 | 21 | // the lambda handler function 22 | let runtime = LambdaRuntime { 23 | (event: Request, context: LambdaContext) -> Response in 24 | 25 | // call the business function and return a response 26 | let result = isPalindrome(event.text) 27 | return Response( 28 | text: event.text, 29 | isPalindrome: result, 30 | message: "Your text is \(result ? "a" : "not a") palindrome" 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-03-07-main.swift: -------------------------------------------------------------------------------- 1 | import AWSLambdaRuntime 2 | 3 | // the data structure to represent the input parameter 4 | struct Request: Decodable { 5 | let text: String 6 | } 7 | 8 | // the data structure to represent the response parameter 9 | struct Response: Encodable { 10 | let text: String 11 | let isPalindrome: Bool 12 | let message: String 13 | } 14 | 15 | // the business function 16 | func isPalindrome(_ text: String) -> Bool { 17 | let cleanedText = text.lowercased().filter { $0.isLetter } 18 | return cleanedText == String(cleanedText.reversed()) 19 | } 20 | 21 | // the lambda handler function 22 | let runtime = LambdaRuntime { 23 | (event: Request, context: LambdaContext) -> Response in 24 | 25 | // call the business function and return a response 26 | let result = isPalindrome(event.text) 27 | return Response( 28 | text: event.text, 29 | isPalindrome: result, 30 | message: "Your text is \(result ? "a" : "not a") palindrome" 31 | ) 32 | } 33 | 34 | // start the runtime 35 | try await runtime.run() 36 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-04-02-console-output.sh: -------------------------------------------------------------------------------- 1 | 2025-01-02T14:59:29+0100 info LocalLambdaServer : [AWSLambdaRuntime] 2 | LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke 3 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-04-03-curl.sh: -------------------------------------------------------------------------------- 1 | curl --header "Content-Type: application/json" \ 2 | --request POST \ 3 | --data '{"text": "Was it a car or a cat I saw?"}' \ 4 | http://127.0.0.1:7000/invoke 5 | 6 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-04-04-curl.sh: -------------------------------------------------------------------------------- 1 | curl --header "Content-Type: application/json" \ 2 | --request POST \ 3 | --data '{"text": "Was it a car or a cat I saw?"}' \ 4 | http://127.0.0.1:7000/invoke 5 | 6 | {"message":"Your text is a palindrome","isPalindrome":true,"text":"Was it a car or a cat I saw?"} 7 | 8 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-04-06-terminal.sh: -------------------------------------------------------------------------------- 1 | swift run 2 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/03-04-07-terminal.sh: -------------------------------------------------------------------------------- 1 | swift run 2 | 3 | Building for debugging... 4 | [1/1] Write swift-version--58304C5D6DBC2206.txt 5 | Build of product 'PalindromeLambda' complete! (0.11s) 6 | 2025-01-02T15:12:49+0100 info LocalLambdaServer : [AWSLambdaRuntime] LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke 7 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-01-02-plugin-archive.sh: -------------------------------------------------------------------------------- 1 | swift package archive --allow-network-connections docker 2 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-01-03-plugin-archive.sh: -------------------------------------------------------------------------------- 1 | swift package archive --allow-network-connections docker 2 | 3 | ------------------------------------------------------------------------- 4 | building "palindrome" in docker 5 | ------------------------------------------------------------------------- 6 | updating "swift:amazonlinux2" docker image 7 | amazonlinux2: Pulling from library/swift 8 | Digest: sha256:df06a50f70e2e87f237bd904d2fc48195742ebda9f40b4a821c4d39766434009 9 | Status: Image is up to date for swift:amazonlinux2 10 | docker.io/library/swift:amazonlinux2 11 | building "PalindromeLambda" 12 | [0/1] Planning build 13 | Building for production... 14 | [0/2] Write swift-version-24593BA9C3E375BF.txt 15 | Build of product 'PalindromeLambda' complete! (1.91s) 16 | ------------------------------------------------------------------------- 17 | archiving "PalindromeLambda" 18 | ------------------------------------------------------------------------- 19 | 1 archive created 20 | * PalindromeLambda at /Users/sst/Palindrome/.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/PalindromeLambda/PalindromeLambda.zip 21 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-01-04-plugin-archive.sh: -------------------------------------------------------------------------------- 1 | swift package archive --allow-network-connections docker 2 | 3 | ------------------------------------------------------------------------- 4 | building "palindrome" in docker 5 | ------------------------------------------------------------------------- 6 | updating "swift:amazonlinux2" docker image 7 | amazonlinux2: Pulling from library/swift 8 | Digest: sha256:df06a50f70e2e87f237bd904d2fc48195742ebda9f40b4a821c4d39766434009 9 | Status: Image is up to date for swift:amazonlinux2 10 | docker.io/library/swift:amazonlinux2 11 | building "PalindromeLambda" 12 | [0/1] Planning build 13 | Building for production... 14 | [0/2] Write swift-version-24593BA9C3E375BF.txt 15 | Build of product 'PalindromeLambda' complete! (1.91s) 16 | ------------------------------------------------------------------------- 17 | archiving "PalindromeLambda" 18 | ------------------------------------------------------------------------- 19 | 1 archive created 20 | * PalindromeLambda at /Users/sst/Palindrome/.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/PalindromeLambda/PalindromeLambda.zip 21 | 22 | cp .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/PalindromeLambda/PalindromeLambda.zip ~/Desktop 23 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-03-01-aws-cli.sh: -------------------------------------------------------------------------------- 1 | aws --version 2 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-03-02-lambda-invoke-hidden.sh: -------------------------------------------------------------------------------- 1 | # --region the AWS Region to send the command 2 | # --function-name the name of your function 3 | # --cli-binary-format tells the cli to use raw data as input (default is base64) 4 | # --payload the payload to pass to your function code 5 | # result.json the name of the file to store the response from the function 6 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-03-02-lambda-invoke.sh: -------------------------------------------------------------------------------- 1 | # --region the AWS Region to send the command 2 | # --function-name the name of your function 3 | # --cli-binary-format tells the cli to use raw data as input (default is base64) 4 | # --payload the payload to pass to your function code 5 | # result.json the name of the file to store the response from the function 6 | 7 | aws lambda invoke \ 8 | --region us-west-2 \ 9 | --function-name PalindromeLambda \ 10 | --cli-binary-format raw-in-base64-out \ 11 | --payload '{"text": "Was it a car or a cat I saw?"}' \ 12 | result.json 13 | 14 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-03-03-lambda-invoke.sh: -------------------------------------------------------------------------------- 1 | # --region the AWS Region to send the command 2 | # --function-name the name of your function 3 | # --cli-binary-format tells the cli to use raw data as input (default is base64) 4 | # --payload the payload to pass to your function code 5 | # result.json the name of the file to store the response from the function 6 | 7 | aws lambda invoke \ 8 | --region us-west-2 \ 9 | --function-name PalindromeLambda \ 10 | --cli-binary-format raw-in-base64-out \ 11 | --payload '{"text": "Was it a car or a cat I saw?"}' \ 12 | result.json 13 | 14 | { 15 | "StatusCode": 200, 16 | "ExecutedVersion": "$LATEST" 17 | } 18 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-03-04-lambda-invoke.sh: -------------------------------------------------------------------------------- 1 | # --region the AWS Region to send the command 2 | # --function-name the name of your function 3 | # --cli-binary-format tells the cli to use raw data as input (default is base64) 4 | # --payload the payload to pass to your function code 5 | # result.json the name of the file to store the response from the function 6 | 7 | aws lambda invoke \ 8 | --region us-west-2 \ 9 | --function-name PalindromeLambda \ 10 | --cli-binary-format raw-in-base64-out \ 11 | --payload '{"text": "Was it a car or a cat I saw?"}' \ 12 | result.json 13 | 14 | { 15 | "StatusCode": 200, 16 | "ExecutedVersion": "$LATEST" 17 | } 18 | 19 | cat result.json 20 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/code/04-03-05-lambda-invoke.sh: -------------------------------------------------------------------------------- 1 | # --region the AWS Region to send the command 2 | # --function-name the name of your function 3 | # --cli-binary-format tells the cli to use raw data as input (default is base64) 4 | # --payload the payload to pass to your function code 5 | # result.json the name of the file to store the response from the function 6 | 7 | aws lambda invoke \ 8 | --region us-west-2 \ 9 | --function-name PalindromeLambda \ 10 | --cli-binary-format raw-in-base64-out \ 11 | --payload '{"text": "Was it a car or a cat I saw?"}' \ 12 | result.json 13 | 14 | { 15 | "StatusCode": 200, 16 | "ExecutedVersion": "$LATEST" 17 | } 18 | 19 | cat result.json 20 | {"text":"Was it a car or a cat I saw?","isPalindrome":true,"message":"Your text is a palindrome"} 21 | 22 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-10-regions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-10-regions.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-20-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-20-dashboard.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-30-create-function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-30-create-function.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-40-select-zip-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-40-select-zip-file.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-50-upload-zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-50-upload-zip.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-60-prepare-test-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-60-prepare-test-event.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-70-view-invocation-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-70-view-invocation-response.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-80-delete-function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-80-delete-function.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-80-delete-role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/deployment/console-80-delete-role.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/00-swift_on_lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/00-swift_on_lambda.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/01-swift_on_lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/01-swift_on_lambda.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-01-terminal-package-init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-01-terminal-package-init.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-01-xcode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-01-xcode@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-01-xcode~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-01-xcode~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-02-swift-package-manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-02-swift-package-manager.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-03-swift-code-xcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-03-swift-code-xcode.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-04-01-compile-run@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-04-01-compile-run@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-04-01-compile-run~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-04-01-compile-run~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-04-test-locally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-04-test-locally.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-swift_on_lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/03-swift_on_lambda.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-01-01-docker-started@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-01-01-docker-started@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-01-compile-for-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-01-compile-for-linux.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-01-console-login@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-01-console-login@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-02-console-login@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-02-console-login@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-03-select-region@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-03-select-region@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-04-select-lambda@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-04-select-lambda@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-04-select-lambda~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-04-select-lambda~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-05-create-function@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-05-create-function@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-05-create-function~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-05-create-function~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-06-create-function@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-06-create-function@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-06-create-function~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-06-create-function~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-07-upload-zip@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-07-upload-zip@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-07-upload-zip~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-07-upload-zip~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-08-upload-zip@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-08-upload-zip@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-08-upload-zip~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-08-upload-zip~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-09-test-lambda@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-09-test-lambda@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-09-test-lambda~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-09-test-lambda~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-10-test-lambda-result@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-10-test-lambda-result@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-10-test-lambda-result~dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-10-test-lambda-result~dark@2x.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-create-lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-02-create-lambda.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-03-invoke-lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-03-invoke-lambda.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-swift_on_lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swift-server/swift-aws-lambda-runtime/41c5edaf041d35b5ff6444a5815443b398bc392b/Sources/AWSLambdaRuntime/Docs.docc/Resources/tutorials/04-swift_on_lambda.png -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/tutorials/01-overview.tutorial: -------------------------------------------------------------------------------- 1 | @Article(time: 1) { 2 | 3 | @Intro(title: "Overview") 4 | 5 | This tutorial helps you to get started writing your first AWS Lambda function in Swift. You will use the `AWSLambdaRuntime` package to write code that can be deployed on AWS Lambda. 6 | 7 | You will learn three things: 8 | 9 | 1. How to implement simple Lambda function and test it locally 10 | 2. How to build a Lambda function for deployment on AWS 11 | 3. How to deploy your Lambda function on AWS and invoke it 12 | 13 | It's a beginners' tutorial. The business logic of the function is very simple, it computes the square of a number passed as input parameter. This simplicity allows you to focus on the project setup and the deployment. You will deploy your code using the AWS Management Console. It is the easiest way to get started with AWS Lambda. 14 | 15 | If you have any questions or recommendations, please [leave your feedback on GitHub](https://github.com/swift-server/swift-aws-lambda-runtime/issues) so that you can get your question answered and this tutorial can be improved. 16 | 17 | *The following instructions were recorded on January 2025 and the AWS Management Console may have changed since then. Feel free to raise an issue if you spot differences with our screenshots* 18 | } -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/tutorials/02-what-is-lambda.tutorial: -------------------------------------------------------------------------------- 1 | @Article(time: 3) { 2 | 3 | @Intro(title: "What is AWS Lambda") 4 | 5 | 6 | AWS Lambda is a compute service that lets you run code without provisioning or managing servers. Lambda runs your code on a high-availability compute infrastructure and performs all of the administration of the compute resources, including server and operating system maintenance, capacity provisioning and automatic scaling, and logging. With Lambda, you can run code for virtually any type of application or backend service. All you need to do is supply your code in [one of the languages that Lambda supports](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html), including Swift. 7 | 8 | You organize your code into [Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-function). Lambda runs your function only when needed and scales automatically, from a few requests per day to thousands per second. You pay only for the compute time that you consume—there is no charge when your code is not running. For more information, see [AWS Lambda Pricing](http://aws.amazon.com/lambda/pricing/). 9 | 10 | Lambda is a highly available service. For more information, see the [AWS Lambda Service Level Agreement](https://aws.amazon.com/lambda/sla/). 11 | 12 | ### When to use AWS Lambda 13 | 14 | Lambda is an ideal compute service for many application scenarios, as long as you can run your application code using the Lambda [standard runtime environment](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html) and within the resources that Lambda provides. For example, you can use Lambda for: 15 | 16 | - Mobile backends: Build backends using Lambda and Amazon API Gateway to authenticate and process API requests. Use AWS Amplify to easily integrate your backend with your iOS, Android, Web, and React Native front ends. 17 | 18 | - Web applications: Combine Lambda with other AWS services to build powerful web applications that automatically scale up and down and run in a highly available configuration across multiple data centers. 19 | 20 | - File processing: Use Amazon Simple Storage Service (Amazon S3) to trigger Lambda data processing in real time after an upload. 21 | 22 | - Stream processing: Use Lambda and Amazon Kinesis to process real-time streaming data for application activity tracking, transaction order processing, click stream analysis, data cleansing, log filtering, indexing, social media analysis, Internet of Things (IoT) device data telemetry, and metering. 23 | 24 | - IoT backends: Build serverless backends using Lambda to handle web, mobile, IoT, and third-party API requests. 25 | 26 | When using Lambda, you are responsible only for your code. Lambda manages the compute fleet that offers a balance of memory, CPU, network, and other resources to run your code. Because Lambda manages these resources, you cannot log in to compute instances or customize the operating system on [provided runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). Lambda performs operational and administrative activities on your behalf, including managing capacity, monitoring, and logging your Lambda functions. 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/tutorials/03-prerequisites.tutorial: -------------------------------------------------------------------------------- 1 | @Article(time: 3) { 2 | 3 | @Intro(title: "Prerequisites") 4 | 5 | 6 | This tutorial has been tested on macOS, since this is what most Swift developers work on. It should also work on Linux. 7 | 8 | To follow the instructions provided by this tutorial you'll need to meet a couple of prerequisites. 9 | 10 | - We expect you to have a basic understanding of the Swift programming language and be somewhat familiar with the terminal/console. You can follow this [guided tour to have an overview of Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/guidedtour). [You can follow this short tutorial to learn about macOS commands and the Terminal](https://support.apple.com/guide/terminal/open-or-quit-terminal-apd5265185d-f365-44cb-8b09-71a064a42125/mac). 11 | 12 | - You'll need to have a text editor and the Swift toolchain installed. On macOS, you can use [Xcode](https://developer.apple.com/xcode/). On Linux, you must install [the Swift runtime and toolchain](https://www.swift.org/download/). On macOS and Linux, you may also use [VSCode](https://code.visualstudio.com/download) and the [Swift extension for VSCode](https://www.swift.org/blog/vscode-extension/). 13 | 14 | - To compile your Lambda function to run on AWS Lambda, you will need to install [Docker](https://docs.docker.com/desktop/install/mac-install/). This tutorial doesn't go into much detail what Docker is and what it does. Just remember that AWS Lambda functions run on Linux. Therefore, you have to compile your Swift Lambda function code for Linux. Docker allows you to start a Linux virtual machine where you will compile your Swift code before to deploy it on AWS Lambda. This tutorial contains all the commands you will have to type to interact with Docker. Follow [the instructions provided by Docker](https://docs.docker.com/desktop/install/mac-install/) to install Docker on your machine. 15 | 16 | - To deploy your Lambda function on AWS you need an [Amazon Web Service (AWS)](https://aws.amazon.com/what-is-aws/) account. [Follow these instructions to create an AWS account](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html). 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Docs.docc/tutorials/table-of-content.tutorial: -------------------------------------------------------------------------------- 1 | @Tutorials(name: "AWS Lambda functions in Swift") { 2 | @Intro(title: "Your First Lambda Function Written in Swift") { 3 | A step-by-step tutorial to learn how to implement, build, test, and deploy your first Lambda function written in Swift. 4 | @Image(source: "00-swift_on_lambda.png", alt: "Swift on AWS Lambda icons") 5 | } 6 | 7 | @Chapter(name: "Before getting started") { 8 | 9 | @Image(source: "01-swift_on_lambda.png", alt: "A Swift project open in Xcode") 10 | An overview of what to expect and what you need before getting started. 11 | @TutorialReference(tutorial: "doc:01-overview") 12 | @TutorialReference(tutorial: "doc:02-what-is-lambda") 13 | @TutorialReference(tutorial: "doc:03-prerequisites") 14 | } 15 | @Chapter(name: "Your first Lambda function in Swift") { 16 | 17 | @Image(source: "03-swift_on_lambda.png", alt: "Swift Icon") 18 | Create your first function and test it locally 19 | @TutorialReference(tutorial: "doc:03-write-function") 20 | } 21 | @Chapter(name: "Deploy your code to the cloud") { 22 | 23 | @Image(source: "04-swift_on_lambda.png", alt: "Deploying Swift into AWS Lambda") 24 | Build, package, upload, and invoke your code on AWS Lambda. 25 | @TutorialReference(tutorial: "doc:04-deploy-function") 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/FoundationSupport/Context+Foundation.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if FoundationJSONSupport 16 | #if canImport(FoundationEssentials) 17 | import FoundationEssentials 18 | #else 19 | import struct Foundation.Date 20 | #endif 21 | 22 | extension LambdaContext { 23 | var deadlineDate: Date { 24 | let secondsSinceEpoch = Double(Int64(bitPattern: self.deadline.rawValue)) / -1_000_000_000 25 | return Date(timeIntervalSince1970: secondsSinceEpoch) 26 | } 27 | } 28 | #endif // trait: FoundationJSONSupport 29 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/Lambda.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2017-2018 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Dispatch 16 | import Logging 17 | import NIOCore 18 | import NIOPosix 19 | 20 | #if os(macOS) 21 | import Darwin.C 22 | #elseif canImport(Glibc) 23 | import Glibc 24 | #elseif canImport(Musl) 25 | import Musl 26 | #elseif os(Windows) 27 | import ucrt 28 | #else 29 | #error("Unsupported platform") 30 | #endif 31 | 32 | public enum Lambda { 33 | @inlinable 34 | package static func runLoop( 35 | runtimeClient: RuntimeClient, 36 | handler: Handler, 37 | logger: Logger 38 | ) async throws where Handler: StreamingLambdaHandler { 39 | var handler = handler 40 | 41 | var logger = logger 42 | do { 43 | while !Task.isCancelled { 44 | let (invocation, writer) = try await runtimeClient.nextInvocation() 45 | logger[metadataKey: "aws-request-id"] = "\(invocation.metadata.requestID)" 46 | 47 | do { 48 | try await handler.handle( 49 | invocation.event, 50 | responseWriter: writer, 51 | context: LambdaContext( 52 | requestID: invocation.metadata.requestID, 53 | traceID: invocation.metadata.traceID, 54 | invokedFunctionARN: invocation.metadata.invokedFunctionARN, 55 | deadline: DispatchWallTime( 56 | millisSinceEpoch: invocation.metadata.deadlineInMillisSinceEpoch 57 | ), 58 | logger: logger 59 | ) 60 | ) 61 | } catch { 62 | try await writer.reportError(error) 63 | continue 64 | } 65 | } 66 | } catch is CancellationError { 67 | // don't allow cancellation error to propagate further 68 | } 69 | } 70 | 71 | /// The default EventLoop the Lambda is scheduled on. 72 | public static let defaultEventLoop: any EventLoop = NIOSingletons.posixEventLoopGroup.next() 73 | } 74 | 75 | // MARK: - Public API 76 | 77 | extension Lambda { 78 | /// Utility to access/read environment variables 79 | public static func env(_ name: String) -> String? { 80 | guard let value = getenv(name) else { 81 | return nil 82 | } 83 | return String(cString: value) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/LambdaRuntime+ServiceLifecycle.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if ServiceLifecycleSupport 16 | import ServiceLifecycle 17 | 18 | extension LambdaRuntime: Service {} 19 | #endif 20 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/LambdaRuntimeClientProtocol.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOCore 16 | 17 | @usableFromInline 18 | package protocol LambdaRuntimeClientResponseStreamWriter: LambdaResponseStreamWriter { 19 | func write(_ buffer: ByteBuffer) async throws 20 | func finish() async throws 21 | func writeAndFinish(_ buffer: ByteBuffer) async throws 22 | func reportError(_ error: any Error) async throws 23 | } 24 | 25 | @usableFromInline 26 | package protocol LambdaRuntimeClientProtocol { 27 | associatedtype Writer: LambdaRuntimeClientResponseStreamWriter 28 | 29 | func nextInvocation() async throws -> (Invocation, Writer) 30 | } 31 | 32 | @usableFromInline 33 | package struct Invocation: Sendable { 34 | @usableFromInline 35 | package var metadata: InvocationMetadata 36 | @usableFromInline 37 | package var event: ByteBuffer 38 | 39 | package init(metadata: InvocationMetadata, event: ByteBuffer) { 40 | self.metadata = metadata 41 | self.event = event 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/AWSLambdaRuntime/LambdaRuntimeError.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | @usableFromInline 16 | package struct LambdaRuntimeError: Error { 17 | @usableFromInline 18 | package enum Code: Sendable { 19 | case closingRuntimeClient 20 | 21 | case connectionToControlPlaneLost 22 | case connectionToControlPlaneGoingAway 23 | case invocationMissingMetadata 24 | 25 | case writeAfterFinishHasBeenSent 26 | case finishAfterFinishHasBeenSent 27 | case lostConnectionToControlPlane 28 | case unexpectedStatusCodeForRequest 29 | 30 | case nextInvocationMissingHeaderRequestID 31 | case nextInvocationMissingHeaderDeadline 32 | case nextInvocationMissingHeaderInvokeFuctionARN 33 | 34 | case missingLambdaRuntimeAPIEnvironmentVariable 35 | case runtimeCanOnlyBeStartedOnce 36 | case invalidPort 37 | } 38 | 39 | @usableFromInline 40 | package init(code: Code, underlying: (any Error)? = nil) { 41 | self.code = code 42 | self.underlying = underlying 43 | } 44 | 45 | @usableFromInline 46 | package var code: Code 47 | @usableFromInline 48 | package var underlying: (any Error)? 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Tests/AWSLambdaRuntimeTests/InvocationTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOHTTP1 16 | import Testing 17 | 18 | @testable import AWSLambdaRuntime 19 | 20 | #if canImport(FoundationEssentials) 21 | import FoundationEssentials 22 | #else 23 | import Foundation 24 | #endif 25 | 26 | @Suite 27 | struct InvocationTest { 28 | @Test 29 | func testInvocationTraceID() throws { 30 | let headers = HTTPHeaders([ 31 | (AmazonHeaders.requestID, "test"), 32 | (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), 33 | (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), 34 | ]) 35 | 36 | var maybeInvocation: InvocationMetadata? 37 | 38 | #expect(throws: Never.self) { maybeInvocation = try InvocationMetadata(headers: headers) } 39 | let invocation = try #require(maybeInvocation) 40 | #expect(!invocation.traceID.isEmpty) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/AWSLambdaRuntimeTests/LambdaRunLoopTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOCore 17 | import Testing 18 | 19 | @testable import AWSLambdaRuntime 20 | 21 | #if canImport(FoundationEssentials) 22 | import FoundationEssentials 23 | #else 24 | import Foundation 25 | #endif 26 | 27 | @Suite 28 | struct LambdaRunLoopTests { 29 | struct MockEchoHandler: StreamingLambdaHandler { 30 | func handle( 31 | _ event: ByteBuffer, 32 | responseWriter: some LambdaResponseStreamWriter, 33 | context: LambdaContext 34 | ) async throws { 35 | context.logger.info("Test") 36 | try await responseWriter.writeAndFinish(event) 37 | } 38 | } 39 | 40 | struct FailingHandler: StreamingLambdaHandler { 41 | func handle( 42 | _ event: ByteBuffer, 43 | responseWriter: some LambdaResponseStreamWriter, 44 | context: LambdaContext 45 | ) async throws { 46 | context.logger.info("Test") 47 | throw LambdaError.handlerError 48 | } 49 | } 50 | 51 | let mockClient = LambdaMockClient() 52 | let mockEchoHandler = MockEchoHandler() 53 | let failingHandler = FailingHandler() 54 | 55 | @Test func testRunLoop() async throws { 56 | let inputEvent = ByteBuffer(string: "Test Invocation Event") 57 | 58 | try await withThrowingTaskGroup(of: Void.self) { group in 59 | let logStore = CollectEverythingLogHandler.LogStore() 60 | group.addTask { 61 | try await Lambda.runLoop( 62 | runtimeClient: self.mockClient, 63 | handler: self.mockEchoHandler, 64 | logger: Logger( 65 | label: "RunLoopTest", 66 | factory: { _ in CollectEverythingLogHandler(logStore: logStore) } 67 | ) 68 | ) 69 | } 70 | 71 | let requestID = UUID().uuidString 72 | let response = try await self.mockClient.invoke(event: inputEvent, requestID: requestID) 73 | #expect(response == inputEvent) 74 | logStore.assertContainsLog("Test", ("aws-request-id", .exactMatch(requestID))) 75 | 76 | group.cancelAll() 77 | } 78 | } 79 | 80 | @Test func testRunLoopError() async throws { 81 | let inputEvent = ByteBuffer(string: "Test Invocation Event") 82 | 83 | await withThrowingTaskGroup(of: Void.self) { group in 84 | let logStore = CollectEverythingLogHandler.LogStore() 85 | group.addTask { 86 | try await Lambda.runLoop( 87 | runtimeClient: self.mockClient, 88 | handler: self.failingHandler, 89 | logger: Logger( 90 | label: "RunLoopTest", 91 | factory: { _ in CollectEverythingLogHandler(logStore: logStore) } 92 | ) 93 | ) 94 | } 95 | 96 | let requestID = UUID().uuidString 97 | await #expect( 98 | throws: LambdaError.handlerError, 99 | performing: { 100 | try await self.mockClient.invoke(event: inputEvent, requestID: requestID) 101 | } 102 | ) 103 | logStore.assertContainsLog("Test", ("aws-request-id", .exactMatch(requestID))) 104 | 105 | group.cancelAll() 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Tests/AWSLambdaRuntimeTests/NewLambda+CodableTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AWSLambdaRuntime 16 | import Logging 17 | import NIOCore 18 | import Testing 19 | 20 | #if canImport(FoundationEssentials) 21 | import FoundationEssentials 22 | #else 23 | import Foundation 24 | #endif 25 | 26 | @Suite 27 | struct JSONTests { 28 | 29 | let logger = Logger(label: "JSONTests") 30 | 31 | struct Foo: Codable { 32 | var bar: String 33 | } 34 | 35 | @Test 36 | func testEncodingConformance() { 37 | let encoder = LambdaJSONOutputEncoder(JSONEncoder()) 38 | let foo = Foo(bar: "baz") 39 | var byteBuffer = ByteBuffer() 40 | 41 | #expect(throws: Never.self) { 42 | try encoder.encode(foo, into: &byteBuffer) 43 | } 44 | 45 | #expect(byteBuffer == ByteBuffer(string: #"{"bar":"baz"}"#)) 46 | } 47 | 48 | @Test 49 | func testJSONHandlerWithOutput() async { 50 | let jsonEncoder = JSONEncoder() 51 | let jsonDecoder = JSONDecoder() 52 | 53 | let closureHandler = ClosureHandler { (foo: Foo, context) in 54 | foo 55 | } 56 | 57 | var handler = LambdaCodableAdapter( 58 | encoder: jsonEncoder, 59 | decoder: jsonDecoder, 60 | handler: LambdaHandlerAdapter(handler: closureHandler) 61 | ) 62 | 63 | let event = ByteBuffer(string: #"{"bar":"baz"}"#) 64 | let writer = MockLambdaWriter() 65 | let context = LambdaContext.__forTestsOnly( 66 | requestID: UUID().uuidString, 67 | traceID: UUID().uuidString, 68 | invokedFunctionARN: "arn:", 69 | timeout: .milliseconds(6000), 70 | logger: self.logger 71 | ) 72 | 73 | await #expect(throws: Never.self) { 74 | try await handler.handle(event, responseWriter: writer, context: context) 75 | } 76 | 77 | let result = await writer.output 78 | #expect(result == ByteBuffer(string: #"{"bar":"baz"}"#)) 79 | } 80 | } 81 | 82 | final actor MockLambdaWriter: LambdaResponseStreamWriter { 83 | private var _buffer: ByteBuffer? 84 | 85 | var output: ByteBuffer? { 86 | self._buffer 87 | } 88 | 89 | func writeAndFinish(_ buffer: ByteBuffer) async throws { 90 | self._buffer = buffer 91 | } 92 | 93 | func write(_ buffer: ByteBuffer) async throws { 94 | fatalError("Unexpected call") 95 | } 96 | 97 | func finish() async throws { 98 | fatalError("Unexpected call") 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Tests/AWSLambdaRuntimeTests/Utils.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2017-2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if canImport(FoundationEssentials) 16 | import FoundationEssentials 17 | #else 18 | import Foundation 19 | #endif 20 | 21 | extension Date { 22 | var millisSinceEpoch: Int64 { 23 | Int64(self.timeIntervalSince1970 * 1000) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/AWSLambdaRuntimeTests/UtilsTest.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftAWSLambdaRuntime open source project 4 | // 5 | // Copyright (c) 2017-2018 Apple Inc. and the SwiftAWSLambdaRuntime project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import XCTest 16 | 17 | @testable import AWSLambdaRuntime 18 | 19 | class UtilsTest: XCTestCase { 20 | func testGenerateXRayTraceID() { 21 | // the time and identifier should be in hexadecimal digits 22 | let invalidCharacters = CharacterSet(charactersIn: "abcdef0123456789").inverted 23 | let numTests = 1000 24 | var values = Set() 25 | for _ in 0.. /proc/sys/kernel/kptr_restrict 22 | 23 | pushd /usr/bin || exit 1 24 | rm -rf perf 25 | ln -s /usr/lib/linux-tools/*/perf perf 26 | popd || exit 1 27 | 28 | pushd /opt || exit 1 29 | git clone https://github.com/brendangregg/FlameGraph.git 30 | popd || exit 1 31 | 32 | # build the code in relase mode with debug symbols 33 | # swift build -c release -Xswiftc -g 34 | # 35 | # run the server 36 | # (.build/release/MockServer) & 37 | # 38 | # strace 39 | # export MAX_REQUESTS=10000 (or MAX_REQUESTS=1 for cold start analysis) 40 | # strace -o .build/strace-c-string-$MAX_REQUESTS -c .build/release/StringSample 41 | # strace -o .build/strace-ffftt-string-$MAX_REQUESTS -fftt .build/release/StringSample 42 | # 43 | # perf 44 | # export MAX_REQUESTS=10000 (or MAX_REQUESTS=1 for cold start analysis) 45 | # perf record -o .build/perf-$MAX_REQUESTS.data -g -F 100000 .build/release/StringSample dwarf 46 | # perf script -i .build/perf-$MAX_REQUESTS.data | /opt/FlameGraph/stackcollapse-perf.pl | swift-demangle | /opt/FlameGraph/flamegraph.pl > .build/flamegraph-$MAX_REQUESTS.svg 47 | -------------------------------------------------------------------------------- /scripts/performance_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftAWSLambdaRuntime open source project 5 | ## 6 | ## Copyright (c) 2017-2022 Apple Inc. and the SwiftAWSLambdaRuntime project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -eu 17 | 18 | export HOST=127.0.0.1 19 | export PORT=3000 20 | export AWS_LAMBDA_RUNTIME_API="$HOST:$PORT" 21 | export LOG_LEVEL=warning # important, otherwise log becomes a bottleneck 22 | 23 | # using gdate on mdarwin for nanoseconds 24 | if [[ $(uname -s) == "Linux" ]]; then 25 | shopt -s expand_aliases 26 | alias gdate="date" 27 | fi 28 | 29 | swift build -c release -Xswiftc -g 30 | LAMBDA_USE_LOCAL_DEPS=../.. swift build --package-path Examples/HelloWorld -c release -Xswiftc -g 31 | LAMBDA_USE_LOCAL_DEPS=../.. swift build --package-path Examples/HelloJSON -c release -Xswiftc -g 32 | 33 | cleanup() { 34 | kill -9 $server_pid # ignore-unacceptable-language 35 | } 36 | 37 | trap "cleanup" ERR 38 | 39 | cold_iterations=1000 40 | warm_iterations=10000 41 | results=() 42 | 43 | #------------------ 44 | # string 45 | #------------------ 46 | 47 | export MODE=string 48 | 49 | # start (fork) mock server 50 | pkill -9 MockServer && echo "killed previous servers" && sleep 1 # ignore-unacceptable-language 51 | echo "starting server in $MODE mode" 52 | (./.build/release/MockServer) & 53 | server_pid=$! 54 | sleep 1 55 | kill -0 $server_pid # check server is alive # ignore-unacceptable-language 56 | 57 | # cold start 58 | echo "running $MODE mode cold test" 59 | cold=() 60 | export MAX_REQUESTS=1 61 | for (( i=0; i /dev/null 62 | sudo apt-get update 63 | 64 | sudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 65 | 66 | # Add the current user to the docker group 67 | sudo usermod -aG docker "$USER" 68 | 69 | # LOGOUT and LOGIN to apply the changes 70 | exit 0 71 | -------------------------------------------------------------------------------- /scripts/ubuntu-test-plugin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftAWSLambdaRuntime open source project 5 | ## 6 | ## Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | # Connect with ssh 17 | 18 | export PATH=/home/ubuntu/swift-6.0.3-RELEASE-ubuntu24.04-aarch64/usr/bin:"${PATH}" 19 | 20 | # clone a project 21 | git clone https://github.com/swift-server/swift-aws-lambda-runtime.git 22 | 23 | # be sure Swift is install. 24 | # Youc an install swift with the following command: ./scripts/ubuntu-install-swift.sh 25 | 26 | # build the project 27 | cd swift-aws-lambda-runtime/Examples/ResourcesPackaging/ || exit 1 28 | LAMBDA_USE_LOCAL_DEPS=../.. swift package archive --allow-network-connections docker 29 | --------------------------------------------------------------------------------