44// snippet-start:[lambda.swift.function.imports]
55import Foundation
66import AWSLambdaRuntime
7- @ preconcurrency import AWSS3
7+ import AWSS3
88
99import protocol AWSClientRuntime. AWSServiceError
1010import enum Smithy. ByteStream
1111// snippet-end:[lambda.swift.function.imports]
12-
1312// snippet-start:[lambda.swift.function.types]
1413// snippet-start:[lambda.swift.function.struct.request]
1514/// Represents the contents of the requests being received from the client.
@@ -20,7 +19,6 @@ struct Request: Decodable, Sendable {
2019 let body : String
2120}
2221// snippet-end:[lambda.swift.function.struct.request]
23-
2422// snippet-start:[lambda.swift.function.struct.response]
2523/// The contents of the response sent back to the client. This must be
2624/// `Encodable`.
@@ -31,92 +29,131 @@ struct Response: Encodable, Sendable {
3129 let body : String
3230}
3331// snippet-end:[lambda.swift.function.struct.response]
34-
3532// snippet-start:[lambda.swift.function.errors]
3633/// The errors that the Lambda function can return.
3734enum S3ExampleLambdaErrors : Error {
3835 /// A required environment variable is missing. The missing variable is
3936 /// specified.
4037 case noEnvironmentVariable( String )
38+ /// The Amazon Simple Storage Service (S3) client couldn't be created.
39+ case noS3Client
4140}
4241// snippet-end:[lambda.swift.function.errors]
4342// snippet-end:[lambda.swift.function.types]
4443
45- let currentRegion = ProcessInfo . processInfo. environment [ " AWS_REGION " ] ?? " us-east-1 "
46- let s3Client = try S3Client ( region: currentRegion)
47-
48- // snippet-start:[lambda.swift.function.putobject]
49- /// Create a new object on Amazon S3 whose name is based on the current
50- /// timestamp, containing the text specified.
51- ///
52- /// - Parameters:
53- /// - body: The text to store in the new S3 object.
54- /// - bucketName: The name of the Amazon S3 bucket to put the new object
55- /// into.
56- ///
57- /// - Throws: Errors from `PutObject`.
58- ///
59- /// - Returns: The name of the new Amazon S3 object that contains the
60- /// specified body text.
61- func putObject( body: String , bucketName: String ) async throws -> String {
62- // Generate an almost certainly unique object name based on the current
63- // timestamp.
64-
65- let objectName = " \( Int ( Date ( ) . timeIntervalSince1970*1_000_000) ) .txt "
66-
67- // Create a Smithy `ByteStream` that represents the string to write into
68- // the bucket.
69-
70- let inputStream = Smithy . ByteStream. data ( body. data ( using: . utf8) )
71-
72- // Store the text into an object in the Amazon S3 bucket.
44+ // snippet-start:[lambda.swift.function.handler]
45+ /// A Swift AWS Lambda Runtime `LambdaHandler` lets you both perform needed
46+ /// initialization and handle AWS Lambda requests. There are other handler
47+ /// protocols available for other use cases.
48+ @main
49+ struct S3ExampleLambda : LambdaHandler {
50+ let s3Client : S3Client ?
51+
52+ // snippet-start:[lambda.swift.function.handler.init]
53+ /// Initialize the AWS Lambda runtime.
54+ ///
55+ /// ^ The logger is a standard Swift logger. You can control the verbosity
56+ /// by setting the `LOG_LEVEL` environment variable.
57+ init ( context: LambdaInitializationContext ) async throws {
58+ // Display the `LOG_LEVEL` configuration for this process.
59+ context. logger. info (
60+ " Log Level env var : \( ProcessInfo . processInfo. environment [ " LOG_LEVEL " ] ?? " info " ) "
61+ )
7362
74- _ = try await s3Client. putObject (
75- input: PutObjectInput (
63+ // Initialize the Amazon S3 client. This single client is used for every
64+ // request.
65+ let currentRegion = ProcessInfo . processInfo. environment [ " AWS_REGION " ] ?? " us-east-1 "
66+ self . s3Client = try ? S3Client ( region: currentRegion)
67+ }
68+ // snippet-end:[lambda.swift.function.handler.init]
69+
70+ // snippet-start:[lambda.swift.function.handler.putobject]
71+ /// Write the specified text into a given Amazon S3 bucket. The object's
72+ /// name is based on the current time.
73+ ///
74+ /// - Parameters:
75+ /// - s3Client: The `S3Client` to use when sending the object to the
76+ /// bucket.
77+ /// - bucketName: The name of the Amazon S3 bucket to put the object
78+ /// into.
79+ /// - body: The string to write into the new object.
80+ ///
81+ /// - Returns: A string indicating the name of the file created in the AWS
82+ /// S3 bucket.
83+ private func putObject( client: S3Client ,
84+ bucketName: String ,
85+ body: String ) async throws -> String {
86+ // Generate an almost certainly unique object name based on the current
87+ // timestamp.
88+ let objectName = " \( Int ( Date ( ) . timeIntervalSince1970*1_000_000) ) .txt "
89+
90+ // Create a Smithy `ByteStream` that represents the string to write into
91+ // the bucket.
92+ let inputStream = Smithy . ByteStream. data ( body. data ( using: . utf8) )
93+
94+ // Store the text into an object in the Amazon S3 bucket.
95+ let putObjectRequest = PutObjectInput (
7696 body: inputStream,
7797 bucket: bucketName,
7898 key: objectName
7999 )
80- )
81-
82- // Return the name of the file
100+ let _ = try await client. putObject ( input: putObjectRequest)
83101
84- return objectName
85- }
86- // snippet-end:[lambda.swift.function.putobject]
87-
88- // snippet-start:[lambda.swift.function.runtime]
89- let runtime = LambdaRuntime {
90- ( event: Request , context: LambdaContext ) async throws -> Response in
91-
92- var responseMessage : String
93-
94- // Get the name of the bucket to write the new object into from the
95- // environment variable `BUCKET_NAME`.
96- guard let bucketName = ProcessInfo . processInfo. environment [ " BUCKET_NAME " ] else {
97- context. logger. error ( " Set the environment variable BUCKET_NAME to the name of the S3 bucket to write files to. " )
98- throw S3ExampleLambdaErrors . noEnvironmentVariable ( " BUCKET_NAME " )
102+ // Return the name of the file.
103+ return objectName
99104 }
100-
101- do {
102- let filename = try await putObject ( body: event. body, bucketName: bucketName)
103-
104- // Generate the response text and update the log.
105- responseMessage = " The Lambda function has successfully stored your data in S3 with name ' \( filename) ' "
106- context. logger. info ( " Data successfully stored in S3. " )
107- } catch let error as AWSServiceError {
108- // Generate the error message and update the log.
109- responseMessage = " The Lambda function encountered an error and your data was not saved. Root cause: \( error. errorCode ?? " " ) - \( error. message ?? " " ) "
110- context. logger. error ( " Failed to upload data to Amazon S3. " )
105+ // snippet-end:[lambda.swift.function.handler.putobject]
106+
107+ // snippet-start:[lambda.swift.function.handler.handle]
108+ /// The Lambda function's entry point. Called by the Lambda runtime.
109+ ///
110+ /// - Parameters:
111+ /// - event: The `Request` describing the request made by the
112+ /// client.
113+ /// - context: A `LambdaContext` describing the context in
114+ /// which the lambda function is running.
115+ ///
116+ /// - Returns: A `Response` object that will be encoded to JSON and sent
117+ /// to the client by the Lambda runtime.
118+ func handle( _ event: Request , context: LambdaContext ) async throws -> Response {
119+ // Get the bucket name from the environment.
120+ guard let bucketName = ProcessInfo . processInfo. environment [ " BUCKET_NAME " ] else {
121+ throw S3ExampleLambdaErrors . noEnvironmentVariable ( " BUCKET_NAME " )
122+ }
123+
124+ // Make sure the `S3Client` is valid.
125+ guard let s3Client else {
126+ throw S3ExampleLambdaErrors . noS3Client
127+ }
128+
129+ // Call the `putObject` function to store the object on Amazon S3.
130+ var responseMessage : String
131+ do {
132+ let filename = try await putObject (
133+ client: s3Client,
134+ bucketName: bucketName,
135+ body: event. body)
136+
137+ // Generate the response text.
138+ responseMessage = " The Lambda function has successfully stored your data in S3 with name \( filename) ' "
139+
140+ // Send the success notification to the logger.
141+ context. logger. info ( " Data successfully stored in S3. " )
142+ } catch let error as AWSServiceError {
143+ // Generate the error message.
144+ responseMessage = " The Lambda function encountered an error and your data was not saved. Root cause: \( error. errorCode ?? " " ) - \( error. message ?? " " ) "
145+
146+ // Send the error message to the logger.
147+ context. logger. error ( " Failed to upload data to Amazon S3. " )
148+ }
149+
150+ // Return the response message. The AWS Lambda runtime will send it to the
151+ // client.
152+ return Response (
153+ req_id: context. requestID,
154+ body: responseMessage)
111155 }
112-
113- return Response ( req_id: context. requestID, body: responseMessage)
156+ // snippet-end:[lambda.swift.function.handler.handle]
114157}
115- // snippet-end:[lambda.swift.function.runtime]
116-
117- // Start up the runtime.
118-
119- // snippet-start:[lambda.swift.function.start]
120- try await runtime. run ( )
121- // snippet-end:[lambda.swift.function.start]
158+ // snippet-end:[lambda.swift.function.handler]
122159// snippet-end:[lambda.swift.function.complete]
0 commit comments