Spec-Zone.ru › Swift

Развёртывание на AWS Lambda с помощью Serverless Application Model (SAM)

Это руководство демонстрирует, как развернуть рабочую нагрузку Swift на стороне сервера на AWS с помощью инструментария AWS Serverless Application Model (SAM). Рабочая нагрузка представляет собой REST API для отслеживания списка задач. Он развёртывает API с помощью Amazon API Gateway. Методы API хранят и извлекают данные в базе данных Amazon DynamoDB с использованием функций AWS Lambda.

Архитектура

Architecture

  • Amazon API Gateway получает запросы API
  • API Gateway вызывает функции Lambda для обработки событий PUT и GET
  • Функции Lambda используют AWS SDK for Swift и Swift AWS Lambda Runtime для извлечения и сохранения элементов в базе данных

Предварительные условия

Для создания этого примера приложения вам потребуются:

  • AWS учётная запись
  • AWS Command Line Interface (AWS CLI) - установите CLI и настройте его с вашими учётными данными AWS
  • AWS SAM CLI - командная утилита для создания серверных нагрузок на AWS
  • Docker Desktop - для компиляции кода Swift в образ Docker

Шаг 1: Создание нового проекта SAM

Проект SAM создаёт ресурсы (функции Lambda, API Gateway и таблицу DynamoDB) в вашей учётной записи AWS. Вы определяете ресурсы в шаблоне YAML.

Создайте папку для вашего проекта и новый файл template.yml.

mkdir swift-lambda-api && cd swift-lambda-api
touch template.yml

Откройте файл template.yml и добавьте следующий код. Просмотрите комментарии в коде, чтобы определить, что создаётся в каждом разделе.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  # DynamoDB table to store your data
  SwiftAPITable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
        Name: id
        Type: String

  # Lambda function to put items to the database
  PutItemFunction:
    Type: AWS::Serverless::Function
    Properties:
      # package the function as a Docker image
      PackageType: Image
      Policies:
        # allow function to read and write to database table
        - DynamoDBCrudPolicy:
            TableName: !Ref SwiftAPITable
      Environment:
        # store database table name as an environment variable
        Variables:
          TABLE_NAME: !Ref SwiftAPITable
      Events:
        # handles the POST /item method of the REST API
        Api:
          Type: HttpApi
          Properties:
            Method: post
            Path: /item
    Metadata:
      # location of the code and Docker file for function
      DockerContext: ./src/put-item
      Dockerfile: Dockerfile
      DockerBuildArgs:
        TARGET_NAME: put-item

  # Lambda function to retrieve items from database
  GetItemsFunction:
    Type: AWS::Serverless::Function
    Properties:
      # package the function as a Docker image
      PackageType: Image
      Policies:
        # allow function to read and write to database table
        - DynamoDBCrudPolicy:
            TableName: !Ref SwiftAPITable
      Environment:
        # store database table name as an environment variable
        Variables:
          TABLE_NAME: !Ref SwiftAPITable
      Events:
        # handles the GET /items method of the REST API
        Api:
          Type: HttpApi
          Properties:
            Method: get
            Path: /items
    Metadata:
      # location of the code and Docker file for function
      DockerContext: ./src/get-items
      Dockerfile: Dockerfile
      DockerBuildArgs:
        TARGET_NAME: get-items

# print API endpoint and name of database table
Outputs:
  SwiftAPIEndpoint:
    Description: "APIGatewayendpointURLforyourapplication"
    Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
  SwiftAPITable:
    Description: "DynamoDBTableName"
    Value: !Ref SwiftAPITable

Шаг 2: Инициализация функций Lambda с помощью SwiftPM

Функции Lambda, написанные на Swift, обрабатывают события API. Функция PutItem обрабатывает запросы POST для добавления элементов в базу данных. Функция GetItems обрабатывает запросы GET для извлечения элементов из базы данных.

Используйте Swift Package Manager для инициализации проекта для каждой функции. Также добавьте Dockerfile в каждую папку.

mkdir -p src/put-item
cd src/put-item
swift package init --type executable
touch Dockerfile

cd ../..

mkdir -p src/get-items
cd src/get-items
swift package init --type executable
touch Dockerfile

Шаг 3: Обновление Dockerfile

Docker используется для компиляции вашего кода Swift и развертывания образа в Lambda. Скопируйте следующий код в Dockerfile, который вы создали в каждой папке функции.

# image used to compile your Swift code
FROM--platform=linux/amd64 public.ecr.aws/docker/library/swift:5.7.2-amazonlinux2asbuilder

ARG TARGET_NAME

RUN yum -y install git jq tar zip openssl-devel
WORKDIR /build-lambda
RUN mkdir -p /Sources/$TARGET_NAME/
RUN mkdir -p /Tests/$TARGET_NAME/
ADD /Sources/ ./Sources/
ADD /Tests/ ./Tests/
COPY Package.swift .
RUN cd /build-lambda && swift package clean && swift build --static-swift-stdlib -c release

# image deplpoyed to AWS Lambda with your compiled executable
FROM public.ecr.aws/lambda/provided:al2-x86_64

ARG TARGET_NAME

RUN mkdir -p /var/task/
RUN mkdir -p /var/runtime/
COPY --from=builder /build-lambda/.build/release/$TARGET_NAME /var/task/lambdaExec
RUN chmod 755 /var/task/lambdaExec
RUN ln -s /var/task/lambdaExec /var/runtime/bootstrap
RUN chmod 755 /var/runtime/bootstrap
WORKDIR /var/task
CMD ["/var/task/lambdaExec"]

Шаг 4: Обновление зависимостей Swift

Ваш проект требует 3 библиотек.

  • swift-aws-lambda-runtime
  • swift-aws-lambda-events
  • aws-sdk-swift

Вы определяете их в файле Package.swift. Замените содержимое файла Package.swift в каждой папке функции следующим кодом.

src/put-item/Sources/put-item/Package.swift

// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "put-item",
    platforms: [.macOS(.v12)],
    dependencies: [
        .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime", branch: "main"),
        .package(url: "https://github.com/swift-server/swift-aws-lambda-events", branch: "main"),
        .package(url: "https://github.com/awslabs/aws-sdk-swift", from: "0.9.1")
    ],
    targets: [
        .executableTarget(
            name: "put-item",
            dependencies: [
                .product(name: "AWSLambdaRuntime",package: "swift-aws-lambda-runtime"),
                .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
                .product(name: "AWSDynamoDB", package: "aws-sdk-swift")
            ]),
        .testTarget(
            name: "put-itemTests",
            dependencies: ["put-item"]),
    ]
)

src/get-items/Sources/get-items/Package.swift

// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "get-items",
    platforms: [.macOS(.v12)],
    dependencies: [
        .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime", branch: "main"),
        .package(url: "https://github.com/swift-server/swift-aws-lambda-events", branch: "main"),
        .package(url: "https://github.com/awslabs/aws-sdk-swift", from: "0.9.1")
    ],
    targets: [
        .executableTarget(
            name: "get-items",
            dependencies: [
                .product(name: "AWSLambdaRuntime",package: "swift-aws-lambda-runtime"),
                .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
                .product(name: "AWSDynamoDB", package: "aws-sdk-swift")
            ]),
        .testTarget(
            name: "get-itemsTests",
            dependencies: ["get-items"]),
    ]
)

Шаг 5: Обновление исходного кода функции Lambda

Замените содержимое основного файла кода для каждого Swift-проекта следующим кодом.

src/put-item/Sources/put-item/put_item.swift

// import the packages required by our function
import Foundation
import AWSLambdaRuntime
import AWSLambdaEvents
import AWSDynamoDB

// define Codable struct for function response
struct Item : Codable {
    var id: String?
    let itemName: String
}

enum FunctionError: Error {
    case envError
}

@main
struct PutItemFunction: SimpleLambdaHandler {

    // Lambda Function handler
    func handle(_ event: APIGatewayV2Request, context: LambdaContext) async throws -> Item {

        print("event received:\(event)")

        // create a client to interact with DynamoDB
        let client = try await DynamoDBClient()

        // obtain DynamoDB table name from function's environment variables
        guard let tableName = ProcessInfo.processInfo.environment["TABLE_NAME"] else {
            throw FunctionError.envError
        }

        // decode data from APIGateway POST into a codable struct
        var item = try JSONDecoder().decode(
            Item.self,
            from: event.body!.data(using: .utf8)!
        )

        // generate a unique id for the key of the item
        item.id = UUID().uuidString

        // use SDK to put the item into the database and return the item with key value
        let input = PutItemInput(item: ["id": .s(item.id!), "itemName": .s(item.itemName)], tableName: tableName)

        _ = try await client.putItem(input: input)

        return item
    }
}

src/get-items/Sources/get_items/get_items.swift

// import the packages required by our function
import Foundation
import AWSLambdaRuntime
import AWSLambdaEvents
import AWSDynamoDB

// define Codable struct for function response
struct Item : Codable {
    var id: String = ""
    var itemName: String = ""
}

enum FunctionError: Error {
    case envError
}

@main
struct GetItemsFunction: SimpleLambdaHandler {

    // Lambda Function handler
    func handle(_ event: APIGatewayV2Request, context: LambdaContext) async throws -> [Item] {

        print("event received:\(event)")

        // create a client to interact with DynamoDB
        let client = try await DynamoDBClient()

        // obtain DynamoDB table name from function's environment variables
        guard let tableName = ProcessInfo.processInfo.environment["TABLE_NAME"] else {
            throw FunctionError.envError
        }

        // use SDK to retrieve items from table
        let input = ScanInput(tableName: tableName)
        let response = try await client.scan(input: input)

        // return items in an array
        return response.items!.map() {i in
            var item = Item()

            if case .s(let value) = i["id"] {
                item.id = value
            }

            if case .s(let value) = i["itemName"] {
                item.itemName = value
            }

            return item
        }
    }
}

Шаг 6: Сборка проекта SAM

Сборка вашего проекта SAM использует Docker на вашем компьютере для компиляции кода Swift в образы Docker. Из корневой папки вашего проекта (swift-lambda-api) выполните следующую команду.

sam build

Шаг 7: Развертывание проекта SAM

Развертывание вашего проекта SAM создаёт функции Lambda, API Gateway и базу данных DynamoDB в вашей учётной записи AWS.

sam deploy --guided

Примите значения по умолчанию для всех запросов, за исключением следующих двух:

PutItemFunction may not have authorization defined, Is this okay? [y/N]: y
GetItemsFunction may not have authorization defined, Is this okay? [y/N]: y

Проект создаёт публичный доступный конечный пункт API. Это предупреждения, которые сообщают вам, что у API нет авторизации. Если вы хотите добавить авторизацию в API, обратитесь к документации SAM.

Шаг 8: Использование вашего API

В конце развертывания SAM отобразит конечную точку вашего API Gateway:

Outputs
----------------------------------------------------------------------------------------
Key                 SwiftAPIEndpoint
Description         API Gateway endpoint URL for your application
Value               https://[your-api-id].execute-api.[your-aws-region].amazonaws.com
----------------------------------------------------------------------------------------

Используйте cURL или инструмент, такой как Postman, для взаимодействия с вашим API. Замените [your-api-endpoint] значением SwiftAPIEndpoint из вывода развертывания.

Добавление элемента в список задач

curl --request POST 'https://[your-api-endpoint]/item' --header 'Content-Type: application/json' --data-raw '{"itemName": "my todo item"}'

Получение элементов из списка задач

curl https://[your-api-endpoint]/items

Очистка

После завершения работы с приложением используйте SAM для удаления его из вашей учётной записи AWS. Ответьте Да (y) на все запросы.

sam delete

The Swift Programming Language, Copyright © 2014-2025 Apple Inc.
Swift and the Swift logo are trademarks of Apple Inc.

Documentation for Swift 6.0.3


https://www.swift.org/documentation/server/guides/deploying/aws-sam-lambda.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API