-
Notifications
You must be signed in to change notification settings - Fork 113
Add support for AppSync events. #187
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
Changes from 4 commits
6073c58
2e6ca2b
1923494
0d5d61e
c28333c
32aaff1
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,129 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftAWSLambdaRuntime open source project | ||
// | ||
// Copyright (c) 2017-2020 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html | ||
public enum AppSync { | ||
public struct Event: Decodable { | ||
public let arguments: [String: ArgumentValue] | ||
|
||
public enum ArgumentValue: Codable { | ||
case string(String) | ||
case dictionary([String: String]) | ||
|
||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.singleValueContainer() | ||
if let strValue = try? container.decode(String.self) { | ||
self = .string(strValue) | ||
} else if let dictionaryValue = try? container.decode([String: String].self) { | ||
self = .dictionary(dictionaryValue) | ||
} else { | ||
throw DecodingError.dataCorruptedError(in: container, debugDescription: """ | ||
Unexpected AppSync argument. | ||
Expected a String or a Dictionary. | ||
""") | ||
} | ||
} | ||
|
||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.singleValueContainer() | ||
switch self { | ||
case .dictionary(let array): | ||
try container.encode(array) | ||
case .string(let str): | ||
try container.encode(str) | ||
} | ||
} | ||
} | ||
|
||
public let request: Request | ||
public struct Request: Decodable { | ||
let headers: HTTPHeaders | ||
} | ||
|
||
public let source: [String: String]? | ||
public let stash: [String: String]? | ||
|
||
public let info: Info | ||
public struct Info: Codable { | ||
public var selectionSetList: [String] | ||
public var selectionSetGraphQL: String | ||
public var parentTypeName: String | ||
public var fieldName: String | ||
public var variables: [String: String] | ||
} | ||
|
||
public let identity: Identity? | ||
public struct Identity: 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. The documentation in https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#aws-appsync-resolver-context-reference-identity says:
Should we model this differently? 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. This is a good point! I've updated the model slightly here to take this all into account. Some updates were needed for AWS_IAM authorization. Please see the latest commit |
||
public struct Claims { | ||
let sub: String | ||
let emailVerified: Bool | ||
let iss: String | ||
let phoneNumberVerified: Bool | ||
let cognitoUsername: String | ||
let aud: String | ||
let eventId: String | ||
let tokenUse: String | ||
let authTime: Int | ||
let phoneNumber: String? | ||
let exp: Int | ||
let iat: Int | ||
let email: String? | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case sub | ||
case emailVerified = "email_verified" | ||
case iss | ||
case phoneNumberVerified = "phone_number_verified" | ||
case cognitoUsername = "cognito:username" | ||
case aud | ||
case eventId = "event_id" | ||
case tokenUse = "token_use" | ||
case authTime = "auth_time" | ||
case phoneNumber = "phone_number" | ||
case exp | ||
case iat | ||
case email | ||
} | ||
} | ||
|
||
public let defaultAuthStrategy: String | ||
public let issuer: String | ||
public let sourceIp: [String] | ||
public let sub: String | ||
public let userName: String? | ||
} | ||
} | ||
} | ||
|
||
public extension AppSync { | ||
enum Response<ResultType: Encodable>: Encodable { | ||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.singleValueContainer() | ||
switch self { | ||
case .array(let array): | ||
try container.encode(array) | ||
case .object(let object): | ||
try container.encode(object) | ||
case .dictionary(let dictionary): | ||
try container.encode(dictionary) | ||
} | ||
} | ||
|
||
case object(ResultType) | ||
case array([ResultType]) | ||
case dictionary([String: ResultType]) | ||
} | ||
|
||
typealias JSONStringResponse = Response<String> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftAWSLambdaRuntime open source project | ||
// | ||
// Copyright (c) 2017-2020 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 AppSyncTests: XCTestCase { | ||
static let exampleEventBody = """ | ||
{ | ||
"arguments": { | ||
"id": "my identifier" | ||
}, | ||
"identity": { | ||
"claims": { | ||
"sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9", | ||
"email_verified": true, | ||
"iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxxx", | ||
"phone_number_verified": false, | ||
"cognito:username": "jdoe", | ||
"aud": "7471s60os7h0uu77i1tk27sp9n", | ||
"event_id": "bc334ed8-a938-4474-b644-9547e304e606", | ||
"token_use": "id", | ||
"auth_time": 1599154213, | ||
"phone_number": "+19999999999", | ||
"exp": 1599157813, | ||
"iat": 1599154213, | ||
"email": "jdoe@email.com" | ||
}, | ||
"defaultAuthStrategy": "ALLOW", | ||
"groups": null, | ||
"issuer": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxxx", | ||
"sourceIp": [ | ||
"1.1.1.1" | ||
], | ||
"sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9", | ||
"username": "jdoe" | ||
}, | ||
"source": null, | ||
"request": { | ||
"headers": { | ||
"x-forwarded-for": "1.1.1.1, 2.2.2.2", | ||
"cloudfront-viewer-country": "US", | ||
"cloudfront-is-tablet-viewer": "false", | ||
"via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", | ||
"cloudfront-forwarded-proto": "https", | ||
"origin": "https://us-west-1.console.aws.amazon.com", | ||
"content-length": "217", | ||
"accept-language": "en-US,en;q=0.9", | ||
"host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", | ||
"x-forwarded-proto": "https", | ||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", | ||
"accept": "*/*", | ||
"cloudfront-is-mobile-viewer": "false", | ||
"cloudfront-is-smarttv-viewer": "false", | ||
"accept-encoding": "gzip, deflate, br", | ||
"referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", | ||
"content-type": "application/json", | ||
"sec-fetch-mode": "cors", | ||
"x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", | ||
"x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", | ||
"authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", | ||
"sec-fetch-dest": "empty", | ||
"x-amz-user-agent": "AWS-Console-AppSync/", | ||
"cloudfront-is-desktop-viewer": "true", | ||
"sec-fetch-site": "cross-site", | ||
"x-forwarded-port": "443" | ||
} | ||
}, | ||
"prev": null, | ||
"info": { | ||
"selectionSetList": [ | ||
"id", | ||
"field1", | ||
"field2" | ||
], | ||
"selectionSetGraphQL": "{ id }", | ||
"parentTypeName": "Mutation", | ||
"fieldName": "createSomething", | ||
"variables": {} | ||
}, | ||
"stash": {} | ||
} | ||
""" | ||
|
||
// MARK: Decoding | ||
|
||
func testRequestDecodingExampleEvent() { | ||
let data = AppSyncTests.exampleEventBody.data(using: .utf8)! | ||
var event: AppSync.Event? | ||
XCTAssertNoThrow(event = try JSONDecoder().decode(AppSync.Event.self, from: data)) | ||
|
||
XCTAssertNotNil(event?.arguments) | ||
XCTAssertEqual(event?.arguments["id"], .string("my identifier")) | ||
XCTAssertEqual(event?.info.fieldName, "createSomething") | ||
XCTAssertEqual(event?.info.parentTypeName, "Mutation") | ||
XCTAssertEqual(event?.info.selectionSetList, ["id", "field1", "field2"]) | ||
XCTAssertEqual(event?.request.headers["accept-language"], "en-US,en;q=0.9") | ||
} | ||
|
||
func testRequestDecodingEventWithSource() { | ||
let eventBody = """ | ||
{ | ||
"arguments": {}, | ||
"identity": null, | ||
"source": { | ||
"name": "Hello", | ||
"id": "1" | ||
}, | ||
"request": { | ||
"headers": { | ||
"x-forwarded-for": "1.1.1.1, 2.2.2.2", | ||
"accept-encoding": "gzip, deflate, br", | ||
"cloudfront-viewer-country": "CA", | ||
"cloudfront-is-tablet-viewer": "false", | ||
"referer": "https://us-west-2.console.aws.amazon.com/", | ||
"via": "2.0 xxxxxx.cloudfront.net (CloudFront)", | ||
"cloudfront-forwarded-proto": "https", | ||
"origin": "https://us-west-2.console.aws.amazon.com", | ||
"x-api-key": "xxxxxxxxxxxxxxxxxxxxx", | ||
"content-type": "application/json", | ||
"x-amzn-trace-id": "Root=1-5fcd9a24-364c62405b418bd53c7984ce", | ||
"x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", | ||
"content-length": "173", | ||
"x-amz-user-agent": "AWS-Console-AppSync/", | ||
"x-forwarded-proto": "https", | ||
"host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-2.amazonaws.com", | ||
"accept-language": "en-ca", | ||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Safari/605.1.15", | ||
"cloudfront-is-desktop-viewer": "true", | ||
"cloudfront-is-mobile-viewer": "false", | ||
"accept": "*/*", | ||
"x-forwarded-port": "443", | ||
"cloudfront-is-smarttv-viewer": "false" | ||
} | ||
}, | ||
"prev": null, | ||
"info": { | ||
"selectionSetList": [ | ||
"address", | ||
"id" | ||
], | ||
"selectionSetGraphQL": "{ address id}", | ||
"parentTypeName": "Customer", | ||
"fieldName": "address", | ||
"variables": {} | ||
}, | ||
"stash": {} | ||
} | ||
""" | ||
|
||
let data = eventBody.data(using: .utf8)! | ||
var event: AppSync.Event? | ||
XCTAssertNoThrow(event = try JSONDecoder().decode(AppSync.Event.self, from: data)) | ||
XCTAssertEqual(event?.source?["name"], "Hello") | ||
XCTAssertTrue(event?.stash?.isEmpty ?? false, "stash dictionary must be empty") | ||
} | ||
} | ||
DwayneCoussement marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
extension AppSync.Event.ArgumentValue: Equatable { | ||
public static func == (lhs: Self, rhs: Self) -> Bool { | ||
switch (lhs, rhs) { | ||
case (.string(let lhsString), .string(let rhsString)): | ||
return lhsString == rhsString | ||
case (.dictionary(let lhsDictionary), .dictionary(let rhsDictionary)): | ||
return lhsDictionary == rhsDictionary | ||
default: | ||
return false | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.