Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 110 additions & 73 deletions swift/example_code/lambda/using-lambda-runtime/Sources/lambda.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
// snippet-start:[lambda.swift.function.imports]
import Foundation
import AWSLambdaRuntime
@preconcurrency import AWSS3
import AWSS3

import protocol AWSClientRuntime.AWSServiceError
import enum Smithy.ByteStream
// snippet-end:[lambda.swift.function.imports]

// snippet-start:[lambda.swift.function.types]
// snippet-start:[lambda.swift.function.struct.request]
/// Represents the contents of the requests being received from the client.
Expand All @@ -20,7 +19,6 @@ struct Request: Decodable, Sendable {
let body: String
}
// snippet-end:[lambda.swift.function.struct.request]

// snippet-start:[lambda.swift.function.struct.response]
/// The contents of the response sent back to the client. This must be
/// `Encodable`.
Expand All @@ -31,92 +29,131 @@ struct Response: Encodable, Sendable {
let body: String
}
// snippet-end:[lambda.swift.function.struct.response]

// snippet-start:[lambda.swift.function.errors]
/// The errors that the Lambda function can return.
enum S3ExampleLambdaErrors: Error {
/// A required environment variable is missing. The missing variable is
/// specified.
case noEnvironmentVariable(String)
/// The Amazon Simple Storage Service (S3) client couldn't be created.
case noS3Client
}
// snippet-end:[lambda.swift.function.errors]
// snippet-end:[lambda.swift.function.types]

let currentRegion = ProcessInfo.processInfo.environment["AWS_REGION"] ?? "us-east-1"
let s3Client = try S3Client(region: currentRegion)

// snippet-start:[lambda.swift.function.putobject]
/// Create a new object on Amazon S3 whose name is based on the current
/// timestamp, containing the text specified.
///
/// - Parameters:
/// - body: The text to store in the new S3 object.
/// - bucketName: The name of the Amazon S3 bucket to put the new object
/// into.
///
/// - Throws: Errors from `PutObject`.
///
/// - Returns: The name of the new Amazon S3 object that contains the
/// specified body text.
func putObject(body: String, bucketName: String) async throws -> String {
// Generate an almost certainly unique object name based on the current
// timestamp.

let objectName = "\(Int(Date().timeIntervalSince1970*1_000_000)).txt"

// Create a Smithy `ByteStream` that represents the string to write into
// the bucket.

let inputStream = Smithy.ByteStream.data(body.data(using: .utf8))

// Store the text into an object in the Amazon S3 bucket.
// snippet-start:[lambda.swift.function.handler]
/// A Swift AWS Lambda Runtime `LambdaHandler` lets you both perform needed
/// initialization and handle AWS Lambda requests. There are other handler
/// protocols available for other use cases.
@main
struct S3ExampleLambda: LambdaHandler {
let s3Client: S3Client?

// snippet-start:[lambda.swift.function.handler.init]
/// Initialize the AWS Lambda runtime.
///
/// ^ The logger is a standard Swift logger. You can control the verbosity
/// by setting the `LOG_LEVEL` environment variable.
init(context: LambdaInitializationContext) async throws {
// Display the `LOG_LEVEL` configuration for this process.
context.logger.info(
"Log Level env var : \(ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "info" )"
)

_ = try await s3Client.putObject(
input: PutObjectInput(
// Initialize the Amazon S3 client. This single client is used for every
// request.
let currentRegion = ProcessInfo.processInfo.environment["AWS_REGION"] ?? "us-east-1"
self.s3Client = try? S3Client(region: currentRegion)
}
// snippet-end:[lambda.swift.function.handler.init]

// snippet-start:[lambda.swift.function.handler.putobject]
/// Write the specified text into a given Amazon S3 bucket. The object's
/// name is based on the current time.
///
/// - Parameters:
/// - s3Client: The `S3Client` to use when sending the object to the
/// bucket.
/// - bucketName: The name of the Amazon S3 bucket to put the object
/// into.
/// - body: The string to write into the new object.
///
/// - Returns: A string indicating the name of the file created in the AWS
/// S3 bucket.
private func putObject(client: S3Client,
bucketName: String,
body: String) async throws -> String {
// Generate an almost certainly unique object name based on the current
// timestamp.
let objectName = "\(Int(Date().timeIntervalSince1970*1_000_000)).txt"

// Create a Smithy `ByteStream` that represents the string to write into
// the bucket.
let inputStream = Smithy.ByteStream.data(body.data(using: .utf8))

// Store the text into an object in the Amazon S3 bucket.
let putObjectRequest = PutObjectInput(
body: inputStream,
bucket: bucketName,
key: objectName
)
)

// Return the name of the file
let _ = try await client.putObject(input: putObjectRequest)

return objectName
}
// snippet-end:[lambda.swift.function.putobject]

// snippet-start:[lambda.swift.function.runtime]
let runtime = LambdaRuntime {
(event: Request, context: LambdaContext) async throws -> Response in

var responseMessage: String

// Get the name of the bucket to write the new object into from the
// environment variable `BUCKET_NAME`.
guard let bucketName = ProcessInfo.processInfo.environment["BUCKET_NAME"] else {
context.logger.error("Set the environment variable BUCKET_NAME to the name of the S3 bucket to write files to.")
throw S3ExampleLambdaErrors.noEnvironmentVariable("BUCKET_NAME")
// Return the name of the file.
return objectName
}

do {
let filename = try await putObject(body: event.body, bucketName: bucketName)

// Generate the response text and update the log.
responseMessage = "The Lambda function has successfully stored your data in S3 with name '\(filename)'"
context.logger.info("Data successfully stored in S3.")
} catch let error as AWSServiceError {
// Generate the error message and update the log.
responseMessage = "The Lambda function encountered an error and your data was not saved. Root cause: \(error.errorCode ?? "") - \(error.message ?? "")"
context.logger.error("Failed to upload data to Amazon S3.")
// snippet-end:[lambda.swift.function.handler.putobject]

// snippet-start:[lambda.swift.function.handler.handle]
/// The Lambda function's entry point. Called by the Lambda runtime.
///
/// - Parameters:
/// - event: The `Request` describing the request made by the
/// client.
/// - context: A `LambdaContext` describing the context in
/// which the lambda function is running.
///
/// - Returns: A `Response` object that will be encoded to JSON and sent
/// to the client by the Lambda runtime.
func handle(_ event: Request, context: LambdaContext) async throws -> Response {
// Get the bucket name from the environment.
guard let bucketName = ProcessInfo.processInfo.environment["BUCKET_NAME"] else {
throw S3ExampleLambdaErrors.noEnvironmentVariable("BUCKET_NAME")
}

// Make sure the `S3Client` is valid.
guard let s3Client else {
throw S3ExampleLambdaErrors.noS3Client
}

// Call the `putObject` function to store the object on Amazon S3.
var responseMessage: String
do {
let filename = try await putObject(
client: s3Client,
bucketName: bucketName,
body: event.body)

// Generate the response text.
responseMessage = "The Lambda function has successfully stored your data in S3 with name \(filename)'"

// Send the success notification to the logger.
context.logger.info("Data successfully stored in S3.")
} catch let error as AWSServiceError {
// Generate the error message.
responseMessage = "The Lambda function encountered an error and your data was not saved. Root cause: \(error.errorCode ?? "") - \(error.message ?? "")"

// Send the error message to the logger.
context.logger.error("Failed to upload data to Amazon S3.")
}

// Return the response message. The AWS Lambda runtime will send it to the
// client.
return Response(
req_id: context.requestID,
body: responseMessage)
}

return Response(req_id: context.requestID, body: responseMessage)
// snippet-end:[lambda.swift.function.handler.handle]
}
// snippet-end:[lambda.swift.function.runtime]

// Start up the runtime.

// snippet-start:[lambda.swift.function.start]
try await runtime.run()
// snippet-end:[lambda.swift.function.start]
// snippet-end:[lambda.swift.function.complete]
// snippet-end:[lambda.swift.function.handler]
// snippet-end:[lambda.swift.function.complete]
Loading