Skip to content
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

chore: kickoff release #3644

Merged
merged 2 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy_package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
token: ${{steps.retrieve-token.outputs.token}}

- name: Setup Ruby
uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
uses: ruby/setup-ruby@22fdc77bf4148f810455b226c90fb81b5cbc00a7 # v1.171.0
with:
ruby-version: '3.2.1'
bundler-cache: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
token: ${{steps.retrieve-token.outputs.token}}

- name: Setup Ruby
uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
uses: ruby/setup-ruby@22fdc77bf4148f810455b226c90fb81b5cbc00a7 # v1.171.0
with:
ruby-version: '3.2.1'
bundler-cache: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy_unstable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
token: ${{steps.retrieve-token.outputs.token}}

- name: Setup Ruby
uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
uses: ruby/setup-ruby@22fdc77bf4148f810455b226c90fb81b5cbc00a7 # v1.171.0
with:
ruby-version: '3.2.1'
bundler-cache: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release_doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
token: ${{steps.retrieve-token.outputs.token}}

- name: Setup Ruby
uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
uses: ruby/setup-ruby@22fdc77bf4148f810455b226c90fb81b5cbc00a7 # v1.171.0
with:
ruby-version: '3.2.1'
bundler-cache: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public struct GraphQLOperationRequest<R: Decodable>: AmplifyOperationRequest {
/// The path to traverse before decoding to `responseType`.
public let decodePath: String?

/// The authorization mode
public let authMode: AuthorizationMode?

/// Options to adjust the behavior of this request, including plugin-options
public let options: Options

Expand All @@ -35,13 +38,15 @@ public struct GraphQLOperationRequest<R: Decodable>: AmplifyOperationRequest {
variables: [String: Any]? = nil,
responseType: R.Type,
decodePath: String? = nil,
authMode: AuthorizationMode? = nil,
options: Options) {
self.apiName = apiName
self.operationType = operationType
self.document = document
self.variables = variables
self.responseType = responseType
self.decodePath = decodePath
self.authMode = authMode
self.options = options
}
}
Expand Down
8 changes: 8 additions & 0 deletions Amplify/Categories/API/Request/GraphQLRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
// SPDX-License-Identifier: Apache-2.0
//

/// Empty protocol for plugins to define specific `AuthorizationMode` types for the request.
public protocol AuthorizationMode { }

/// GraphQL Request
public struct GraphQLRequest<R: Decodable> {

Expand All @@ -21,6 +24,9 @@ public struct GraphQLRequest<R: Decodable> {
/// Type to decode the graphql response data object to
public let responseType: R.Type

/// The authorization mode
public let authMode: AuthorizationMode?

/// The path to decode to the graphQL response data to `responseType`. Delimited by `.` The decode path
/// "listTodos.items" will traverse to the object at `listTodos`, and decode the object at `items` to `responseType`
/// The data at that decode path is a list of Todo objects so `responseType` should be `[Todo].self`
Expand All @@ -34,11 +40,13 @@ public struct GraphQLRequest<R: Decodable> {
variables: [String: Any]? = nil,
responseType: R.Type,
decodePath: String? = nil,
authMode: AuthorizationMode? = nil,
options: GraphQLRequest<R>.Options? = nil) {
self.apiName = apiName
self.document = document
self.variables = variables
self.responseType = responseType
self.authMode = authMode
self.decodePath = decodePath
self.options = options
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final public class AWSGraphQLOperation<R: Decodable>: GraphQLOperation<R> {
}

let urlRequest = validateRequest(request).flatMap(buildURLRequest(from:))
let finalRequest = await getEndpointInterceptors(from: request).flatMapAsync { requestInterceptors in
let finalRequest = await getEndpointInterceptors().flatMapAsync { requestInterceptors in
let preludeInterceptors = requestInterceptors?.preludeInterceptors ?? []
let customerInterceptors = requestInterceptors?.interceptors ?? []
let postludeInterceptors = requestInterceptors?.postludeInterceptors ?? []
Expand Down Expand Up @@ -150,7 +150,7 @@ final public class AWSGraphQLOperation<R: Decodable>: GraphQLOperation<R> {
}
}

private func getEndpointInterceptors(from request: GraphQLOperationRequest<R>) -> Result<AWSAPIEndpointInterceptors?, APIError> {
func getEndpointInterceptors() -> Result<AWSAPIEndpointInterceptors?, APIError> {
getEndpointConfig(from: request).flatMap { endpointConfig in
do {
if let pluginOptions = request.options.pluginOptions as? AWSAPIPluginDataStoreOptions,
Expand All @@ -159,6 +159,11 @@ final public class AWSGraphQLOperation<R: Decodable>: GraphQLOperation<R> {
withConfig: endpointConfig,
authType: authType
))
} else if let authType = request.authMode as? AWSAuthorizationType {
return .success(try pluginConfig.interceptorsForEndpoint(
withConfig: endpointConfig,
authType: authType
))
} else {
return .success(pluginConfig.interceptorsForEndpoint(withConfig: endpointConfig))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,21 @@ public class AWSGraphQLSubscriptionTaskRunner<R: Decodable>: InternalTaskRunner,
return
}

let pluginOptions = request.options.pluginOptions as? AWSAPIPluginDataStoreOptions
let authType: AWSAuthorizationType?
if let pluginOptions = request.options.pluginOptions as? AWSAPIPluginDataStoreOptions {
authType = pluginOptions.authType
} else if let authorizationMode = request.authMode as? AWSAuthorizationType {
authType = authorizationMode
} else {
authType = nil
}
// Retrieve the subscription connection
do {
self.appSyncClient = try await appSyncClientFactory.getAppSyncRealTimeClient(
for: endpointConfig,
endpoint: endpointConfig.baseURL,
authService: authService,
authType: pluginOptions?.authType,
authType: authType,
apiAuthProviderFactory: apiAuthProviderFactory
)

Expand Down Expand Up @@ -262,14 +269,21 @@ final public class AWSGraphQLSubscriptionOperation<R: Decodable>: GraphQLSubscri
return
}

let pluginOptions = request.options.pluginOptions as? AWSAPIPluginDataStoreOptions
let authType: AWSAuthorizationType?
if let pluginOptions = request.options.pluginOptions as? AWSAPIPluginDataStoreOptions {
authType = pluginOptions.authType
} else if let authorizationMode = request.authMode as? AWSAuthorizationType {
authType = authorizationMode
} else {
authType = nil
}
Task {
do {
appSyncRealTimeClient = try await appSyncRealTimeClientFactory.getAppSyncRealTimeClient(
for: endpointConfig,
endpoint: endpointConfig.baseURL,
authService: authService,
authType: pluginOptions?.authType,
authType: authType,
apiAuthProviderFactory: apiAuthProviderFactory
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ extension GraphQLRequest {
variables: variables,
responseType: responseType,
decodePath: decodePath,
authMode: authMode,
options: requestOptions)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
import XCTest
import Amplify
@testable import AWSAPIPlugin
import AWSPluginsCore

class AWSAPICategoryPluginGraphQLBehaviorTests: AWSAPICategoryPluginTestBase {

// MARK: Query API Tests

func testQuery() {
let operationFinished = expectation(description: "Operation should finish")
let request = GraphQLRequest(apiName: apiName,
document: testDocument,
variables: nil,
responseType: JSONValue.self)
let request = GraphQLRequest<JSONValue>(apiName: apiName,
document: testDocument,
variables: nil,
responseType: JSONValue.self,
authMode: AWSAuthorizationType.apiKey)
let operation = apiPlugin.query(request: request) { _ in
operationFinished.fulfill()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import XCTest
@testable import Amplify
@testable import AmplifyTestCommon
@testable import AWSAPIPlugin
@testable import AWSPluginsTestCommon
import AWSPluginsCore

class AWSGraphQLOperationTests: AWSAPICategoryPluginTestBase {

Expand Down Expand Up @@ -37,4 +39,44 @@ class AWSGraphQLOperationTests: AWSAPICategoryPluginTestBase {
XCTAssertNil(task)
}


/// Request for `.amazonCognitoUserPool` at runtime with `request` while passing in what
/// is configured as `.apiKey`. Expect that the interceptor is the token interceptor
func testGetEndpointInterceptors() throws {
let request = GraphQLRequest<JSONValue>(apiName: apiName,
document: testDocument,
variables: nil,
responseType: JSONValue.self,
authMode: AWSAuthorizationType.amazonCognitoUserPools)
let task = try OperationTestBase.makeSingleValueErrorMockTask()
let mockSession = MockURLSession(onTaskForRequest: { _ in task })
let pluginConfig = AWSAPICategoryPluginConfiguration(
endpoints: [
apiName: try .init(
name: apiName,
baseURL: URL(string: "url")!,
region: "us-test-1",
authorizationType: .apiKey,
endpointType: .graphQL,
apiKey: "apiKey",
apiAuthProviderFactory: .init())],
apiAuthProviderFactory: .init(),
authService: MockAWSAuthService())
let operation = AWSGraphQLOperation(request: request.toOperationRequest(operationType: .query),
session: mockSession,
mapper: OperationTaskMapper(),
pluginConfig: pluginConfig,
resultListener: { _ in })

// Act
let results = operation.getEndpointInterceptors()

// Assert
guard case let .success(interceptors) = results,
let interceptor = interceptors?.preludeInterceptors.first,
(interceptor as? AuthTokenURLRequestInterceptor) != nil else {
XCTFail("Should be token interceptor for Cognito User Pool")
return
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class OperationTestBase: XCTestCase {
}

func setUpPluginForSingleError(for endpointType: AWSAPICategoryPluginEndpointType) throws {
let task = try makeSingleValueErrorMockTask()
let task = try Self.makeSingleValueErrorMockTask()
let mockSession = MockURLSession(onTaskForRequest: { _ in task })
let sessionFactory = MockSessionFactory(returning: mockSession)
try setUpPlugin(sessionFactory: sessionFactory, endpointType: endpointType)
Expand Down Expand Up @@ -102,7 +102,7 @@ class OperationTestBase: XCTestCase {
return task
}

func makeSingleValueErrorMockTask() throws -> MockURLSessionTask {
static func makeSingleValueErrorMockTask() throws -> MockURLSessionTask {
var mockTask: MockURLSessionTask!
mockTask = MockURLSessionTask(onResume: {
guard let mockSession = mockTask.mockSession,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
//

import Foundation
import Amplify

// swiftlint:disable line_length

/// The types of authorization one can use while talking to an Amazon AppSync
/// GraphQL backend, or an Amazon API Gateway endpoint.
///
/// - SeeAlso: [https://docs.aws.amazon.com/appsync/latest/devguide/security.html](AppSync Security)
public enum AWSAuthorizationType: String {
public enum AWSAuthorizationType: String, AuthorizationMode {

/// For public APIs
case none = "NONE"
Expand Down
Loading
Loading