Skip to content

Commit ee65380

Browse files
committed
Added AWSLambdaEvents library
fixed a stupid bug Remove bytebuffer usages.
1 parent ac29098 commit ee65380

16 files changed

+1757
-166
lines changed

Package.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ let package = Package(
2424
.product(name: "NIOFoundationCompat", package: "swift-nio"),
2525
]),
2626
.testTarget(name: "AWSLambdaRuntimeTests", dependencies: ["AWSLambdaRuntime"]),
27-
.target(name: "AWSLambdaEvents", dependencies: []),
27+
.target(name: "AWSLambdaEvents", dependencies: [
28+
.product(name: "NIOHTTP1", package: "swift-nio"),
29+
.product(name: "NIOFoundationCompat", package: "swift-nio"),
30+
]),
2831
.testTarget(name: "AWSLambdaEventsTests", dependencies: ["AWSLambdaEvents"]),
2932
// samples
3033
.target(name: "StringSample", dependencies: ["AWSLambdaRuntime"]),

Sources/AWSLambdaEvents/ALB.swift

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2017-2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import class Foundation.JSONEncoder
16+
import NIOHTTP1
17+
18+
// https://github.com/aws/aws-lambda-go/blob/master/events/alb.go
19+
public enum ALB {
20+
/// ALBTargetGroupRequest contains data originating from the ALB Lambda target group integration
21+
public struct TargetGroupRequest: DecodableBody {
22+
/// ALBTargetGroupRequestContext contains the information to identify the load balancer invoking the lambda
23+
public struct Context: Codable {
24+
public let elb: ELBContext
25+
}
26+
27+
public let httpMethod: HTTPMethod
28+
public let path: String
29+
public let queryStringParameters: [String: [String]]
30+
public let headers: HTTPHeaders
31+
public let requestContext: Context
32+
public let isBase64Encoded: Bool
33+
public let body: String?
34+
}
35+
36+
/// ELBContext contains the information to identify the ARN invoking the lambda
37+
public struct ELBContext: Codable {
38+
public let targetGroupArn: String
39+
}
40+
41+
public struct TargetGroupResponse {
42+
public let statusCode: HTTPResponseStatus
43+
public let statusDescription: String?
44+
public let headers: HTTPHeaders?
45+
public let body: String
46+
public let isBase64Encoded: Bool
47+
48+
public init(
49+
statusCode: HTTPResponseStatus,
50+
statusDescription: String? = nil,
51+
headers: HTTPHeaders? = nil,
52+
body: String = "",
53+
isBase64Encoded: Bool = false
54+
) {
55+
self.statusCode = statusCode
56+
self.statusDescription = statusDescription
57+
self.headers = headers
58+
self.body = body
59+
self.isBase64Encoded = isBase64Encoded
60+
}
61+
}
62+
}
63+
64+
// MARK: - Request -
65+
66+
extension ALB.TargetGroupRequest: Decodable {
67+
enum CodingKeys: String, CodingKey {
68+
case httpMethod
69+
case path
70+
case queryStringParameters
71+
case multiValueQueryStringParameters
72+
case headers
73+
case multiValueHeaders
74+
case requestContext
75+
case isBase64Encoded
76+
case body
77+
}
78+
79+
public init(from decoder: Decoder) throws {
80+
let container = try decoder.container(keyedBy: CodingKeys.self)
81+
82+
let method = try container.decode(String.self, forKey: .httpMethod)
83+
self.httpMethod = HTTPMethod(rawValue: method)
84+
85+
self.path = try container.decode(String.self, forKey: .path)
86+
87+
// crazy multiple headers
88+
// https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers
89+
90+
if let multiValueQueryStringParameters =
91+
try container.decodeIfPresent([String: [String]].self, forKey: .multiValueQueryStringParameters) {
92+
self.queryStringParameters = multiValueQueryStringParameters
93+
} else {
94+
let singleValueQueryStringParameters = try container.decode(
95+
[String: String].self,
96+
forKey: .queryStringParameters
97+
)
98+
self.queryStringParameters = singleValueQueryStringParameters.mapValues { [$0] }
99+
}
100+
101+
if let multiValueHeaders =
102+
try container.decodeIfPresent([String: [String]].self, forKey: .multiValueHeaders) {
103+
self.headers = HTTPHeaders(awsHeaders: multiValueHeaders)
104+
} else {
105+
let singleValueHeaders = try container.decode(
106+
[String: String].self,
107+
forKey: .headers
108+
)
109+
let multiValueHeaders = singleValueHeaders.mapValues { [$0] }
110+
self.headers = HTTPHeaders(awsHeaders: multiValueHeaders)
111+
}
112+
113+
self.requestContext = try container.decode(Context.self, forKey: .requestContext)
114+
self.isBase64Encoded = try container.decode(Bool.self, forKey: .isBase64Encoded)
115+
116+
let body = try container.decode(String.self, forKey: .body)
117+
self.body = body != "" ? body : nil
118+
}
119+
}
120+
121+
// MARK: - Response -
122+
123+
extension ALB.TargetGroupResponse: Encodable {
124+
static let MultiValueHeadersEnabledKey =
125+
CodingUserInfoKey(rawValue: "ALB.TargetGroupResponse.MultiValueHeadersEnabledKey")!
126+
127+
enum CodingKeys: String, CodingKey {
128+
case statusCode
129+
case statusDescription
130+
case headers
131+
case multiValueHeaders
132+
case body
133+
case isBase64Encoded
134+
}
135+
136+
public func encode(to encoder: Encoder) throws {
137+
var container = encoder.container(keyedBy: CodingKeys.self)
138+
try container.encode(statusCode.code, forKey: .statusCode)
139+
140+
let multiValueHeaderSupport =
141+
encoder.userInfo[ALB.TargetGroupResponse.MultiValueHeadersEnabledKey] as? Bool ?? false
142+
143+
switch (multiValueHeaderSupport, headers) {
144+
case (true, .none):
145+
try container.encode([String: String](), forKey: .multiValueHeaders)
146+
case (false, .none):
147+
try container.encode([String: [String]](), forKey: .headers)
148+
case (true, .some(let headers)):
149+
var multiValueHeaders: [String: [String]] = [:]
150+
headers.forEach { name, value in
151+
var values = multiValueHeaders[name] ?? []
152+
values.append(value)
153+
multiValueHeaders[name] = values
154+
}
155+
try container.encode(multiValueHeaders, forKey: .multiValueHeaders)
156+
case (false, .some(let headers)):
157+
var singleValueHeaders: [String: String] = [:]
158+
headers.forEach { name, value in
159+
singleValueHeaders[name] = value
160+
}
161+
try container.encode(singleValueHeaders, forKey: .headers)
162+
}
163+
164+
try container.encodeIfPresent(statusDescription, forKey: .statusDescription)
165+
try container.encodeIfPresent(body, forKey: .body)
166+
try container.encodeIfPresent(isBase64Encoded, forKey: .isBase64Encoded)
167+
}
168+
}
169+
170+
extension ALB.TargetGroupResponse {
171+
public init<Payload: Encodable>(
172+
statusCode: HTTPResponseStatus,
173+
statusDescription: String? = nil,
174+
headers: HTTPHeaders? = nil,
175+
payload: Payload,
176+
encoder: JSONEncoder = JSONEncoder()
177+
) throws {
178+
var headers = headers ?? HTTPHeaders()
179+
if !headers.contains(name: "Content-Type") {
180+
headers.add(name: "Content-Type", value: "application/json")
181+
}
182+
183+
self.statusCode = statusCode
184+
self.statusDescription = statusDescription
185+
self.headers = headers
186+
187+
let data = try encoder.encode(payload)
188+
self.body = String(decoding: data, as: Unicode.UTF8.self)
189+
self.isBase64Encoded = false
190+
}
191+
192+
public init(
193+
statusCode: HTTPResponseStatus,
194+
statusDescription: String? = nil,
195+
headers: HTTPHeaders? = nil,
196+
bytes: [UInt8]?
197+
) {
198+
let headers = headers ?? HTTPHeaders()
199+
200+
self.statusCode = statusCode
201+
self.statusDescription = statusDescription
202+
self.headers = headers
203+
if let bytes = bytes {
204+
self.body = String(base64Encoding: bytes)
205+
} else {
206+
self.body = ""
207+
}
208+
self.isBase64Encoded = true
209+
}
210+
}

0 commit comments

Comments
 (0)