|
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