-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add (API Gateway) WebSockets Support to Swift for AWS Lambda Events #38
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftAWSLambdaRuntime open source project | ||
// | ||
// Copyright (c) YEARS Apple Inc. and the SwiftAWSLambdaRuntime project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
/// `APIGatewayWebSocketRequest` is a variation of the`APIGatewayV2Request` | ||
/// and contains data coming from the WebSockets API Gateway. | ||
public struct APIGatewayWebSocketRequest: Codable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can any of this vibe shared with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh sure ... much of it can be. I just wasn't sure what the correct approach should be. I kind of aimed for a "what's the minimum to make it work" approach. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably some shared struct they can both include as the underlying implementation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it would be helpful, I would be happy to look at the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it would be helpful, I would be happy to look at the |
||
/// `Context` contains information to identify the AWS account and resources invoking the Lambda function. | ||
public struct Context: Codable { | ||
public struct Identity: Codable { | ||
let sourceIp: String | ||
} | ||
|
||
let routeKey: String | ||
let eventType: String | ||
let extendedRequestId: String | ||
/// The request time in format: 23/Apr/2020:11:08:18 +0000 | ||
let requestTime: String | ||
let messageDirection: String | ||
let stage: String | ||
let connectedAt: UInt64 | ||
let requestTimeEpoch: UInt64 | ||
let identity: Identity | ||
let requestId: String | ||
let domainName: String | ||
let connectionId: String | ||
let apiId: String | ||
} | ||
|
||
public let headers: HTTPHeaders? | ||
public let multiValueHeaders: HTTPMultiValueHeaders? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also see
come through on a CONNECT event type |
||
public let context: Context | ||
public let body: String? | ||
public let isBase64Encoded: Bool? | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case headers | ||
case multiValueHeaders | ||
case context = "requestContext" | ||
case body | ||
case isBase64Encoded | ||
} | ||
} | ||
|
||
/// `APIGatewayWebSocketResponse` is a type alias for `APIGatewayV2Request`. | ||
/// Typically, lambda WebSockets servers send clients data via | ||
/// the ApiGatewayManagementApi mechanism. However, APIGateway does require | ||
/// lambda servers to return some kind of status when APIGateway invokes them. | ||
/// This can be as simple as always returning a 200 "OK" response for all | ||
/// WebSockets requests (the ApiGatewayManagementApi can return any errors to | ||
/// WebSockets clients). | ||
public typealias APIGatewayWebSocketResponse = APIGatewayV2Response | ||
|
||
#if swift(>=5.6) | ||
extension APIGatewayWebSocketRequest: Sendable {} | ||
extension APIGatewayWebSocketRequest.Context: Sendable {} | ||
extension APIGatewayWebSocketRequest.Context.Identity: Sendable {} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftAWSLambdaRuntime open source project | ||
// | ||
// Copyright (c) YEARS Apple Inc. and the SwiftAWSLambdaRuntime project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
@testable import AWSLambdaEvents | ||
import XCTest | ||
|
||
class APIGatewayWebSocketsTests: XCTestCase { | ||
static let exampleConnectEventBody = """ | ||
{ | ||
"headers": { | ||
"Host": "lqrlmblaa2.execute-api.us-east-1.amazonaws.com", | ||
"Origin": "wss://lqrlmblaa2.execute-api.us-east-1.amazonaws.com", | ||
"Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits; server_max_window_bits=15", | ||
"Sec-WebSocket-Key": "am5ubWVpbHd3bmNyYXF0ag==", | ||
"Sec-WebSocket-Version": "13", | ||
"X-Amzn-Trace-Id": "Root=1-64b83950-42de8e247b4c2b43091ef67c", | ||
"X-Forwarded-For": "24.148.42.16", | ||
"X-Forwarded-Port": "443", | ||
"X-Forwarded-Proto": "https" | ||
}, | ||
"multiValueHeaders": { | ||
"Host": [ "lqrlmblaa2.execute-api.us-east-1.amazonaws.com" ], | ||
"Origin": [ "wss://lqrlmblaa2.execute-api.us-east-1.amazonaws.com" ], | ||
"Sec-WebSocket-Extensions": [ | ||
"permessage-deflate; client_max_window_bits; server_max_window_bits=15" | ||
], | ||
"Sec-WebSocket-Key": [ "am5ubWVpbHd3bmNyYXF0ag==" ], | ||
"Sec-WebSocket-Version": [ "13" ], | ||
"X-Amzn-Trace-Id": [ "Root=1-64b83950-42de8e247b4c2b43091ef67c" ], | ||
"X-Forwarded-For": [ "24.148.42.16" ], | ||
"X-Forwarded-Port": [ "443" ], | ||
"X-Forwarded-Proto": [ "https" ] | ||
}, | ||
"requestContext": { | ||
"routeKey": "$connect", | ||
"eventType": "CONNECT", | ||
"extendedRequestId": "IU3kkGyEoAMFwZQ=", | ||
"requestTime": "19/Jul/2023:19:28:16 +0000", | ||
"messageDirection": "IN", | ||
"stage": "dev", | ||
"connectedAt": 1689794896145, | ||
"requestTimeEpoch": 1689794896162, | ||
"identity": { "sourceIp": "24.148.42.16" }, | ||
"requestId": "IU3kkGyEoAMFwZQ=", | ||
"domainName": "lqrlmblaa2.execute-api.us-east-1.amazonaws.com", | ||
"connectionId": "IU3kkeN4IAMCJwA=", | ||
"apiId": "lqrlmblaa2" | ||
}, | ||
"isBase64Encoded": false | ||
} | ||
""" | ||
|
||
// MARK: - Request - | ||
|
||
// MARK: Decoding | ||
|
||
func testRequestDecodingExampleConnectRequest() { | ||
let data = APIGatewayWebSocketsTests.exampleConnectEventBody.data(using: .utf8)! | ||
var req: APIGatewayWebSocketRequest? | ||
XCTAssertNoThrow(req = try JSONDecoder().decode(APIGatewayWebSocketRequest.self, from: data)) | ||
|
||
XCTAssertEqual(req?.context.routeKey, "$connect") | ||
XCTAssertEqual(req?.context.connectionId, "IU3kkeN4IAMCJwA=") | ||
XCTAssertNil(req?.body) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.