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