Skip to content

Commit 86c7e5f

Browse files
committed
add Amplify components for AppSync
1 parent e41df42 commit 86c7e5f

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

Amplify/Core/Configuration/AmplifyOutputsData.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ public struct AmplifyOutputsData: Codable {
251251
public struct AmplifyOutputs {
252252

253253
/// A closure that resolves the `AmplifyOutputsData` configuration
254-
let resolveConfiguration: () throws -> AmplifyOutputsData
254+
@_spi(InternalAmplifyConfiguration)
255+
public let resolveConfiguration: () throws -> AmplifyOutputsData
255256

256257
/// Resolves configuration with `amplify_outputs.json` in the main bundle.
257258
public static let amplifyOutputs: AmplifyOutputs = {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
import AWSClientRuntime // AWSClientRuntime.CredentialsProviding
10+
import ClientRuntime // SdkHttpRequestBuilder
11+
import InternalAmplifyCredentials // AmplifyAWSCredentialsProvider()
12+
import AwsCommonRuntimeKit // CommonRuntimeKit.initialize()
13+
14+
extension AWSCognitoAuthPlugin {
15+
16+
public static func createAppSyncSigner(region: String) -> ((URLRequest) async throws -> URLRequest) {
17+
return { request in
18+
try await signAppSyncRequest(request, region: region)
19+
}
20+
}
21+
public static func signAppSyncRequest(_ urlRequest: URLRequest,
22+
region: Swift.String,
23+
credentialsProvider: AWSClientRuntime.CredentialsProviding = AmplifyAWSCredentialsProvider(),
24+
signingName: Swift.String = "appsync",
25+
date: ClientRuntime.Date = Date()) async throws -> URLRequest {
26+
CommonRuntimeKit.initialize()
27+
28+
// Convert URLRequest to SDK's HTTPRequest
29+
guard let requestBuilder = try createAppSyncSdkHttpRequestBuilder(
30+
urlRequest: urlRequest) else {
31+
return urlRequest
32+
}
33+
34+
// Retrieve the credentials from credentials provider
35+
let credentials = try await credentialsProvider.getCredentials()
36+
37+
// Prepare signing
38+
let flags = SigningFlags(useDoubleURIEncode: true,
39+
shouldNormalizeURIPath: true,
40+
omitSessionToken: false)
41+
let signedBodyHeader: AWSSignedBodyHeader = .none
42+
let signedBodyValue: AWSSignedBodyValue = .empty
43+
let signingConfig = AWSSigningConfig(credentials: credentials,
44+
signedBodyHeader: signedBodyHeader,
45+
signedBodyValue: signedBodyValue,
46+
flags: flags,
47+
date: date,
48+
service: signingName,
49+
region: region,
50+
signatureType: .requestHeaders,
51+
signingAlgorithm: .sigv4)
52+
53+
// Sign request
54+
guard let httpRequest = await AWSSigV4Signer.sigV4SignedRequest(
55+
requestBuilder: requestBuilder,
56+
57+
signingConfig: signingConfig
58+
) else {
59+
return urlRequest
60+
}
61+
62+
// Update original request with new headers
63+
return setHeaders(from: httpRequest, to: urlRequest)
64+
}
65+
66+
static func setHeaders(from sdkRequest: SdkHttpRequest, to urlRequest: URLRequest) -> URLRequest {
67+
var urlRequest = urlRequest
68+
for header in sdkRequest.headers.headers {
69+
urlRequest.setValue(header.value.joined(separator: ","), forHTTPHeaderField: header.name)
70+
}
71+
return urlRequest
72+
}
73+
74+
static func createAppSyncSdkHttpRequestBuilder(urlRequest: URLRequest) throws -> SdkHttpRequestBuilder? {
75+
76+
guard let url = urlRequest.url,
77+
let host = url.host else {
78+
return nil
79+
}
80+
81+
var headers = urlRequest.allHTTPHeaderFields ?? [:]
82+
headers.updateValue(host, forKey: "host")
83+
84+
let httpMethod = (urlRequest.httpMethod?.uppercased())
85+
.flatMap(HttpMethodType.init(rawValue:)) ?? .get
86+
87+
let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?
88+
.map { ClientRuntime.SDKURLQueryItem(name: $0.name, value: $0.value)} ?? []
89+
90+
let requestBuilder = SdkHttpRequestBuilder()
91+
.withHost(host)
92+
.withPath(url.path)
93+
.withQueryItems(queryItems)
94+
.withMethod(httpMethod)
95+
.withPort(443)
96+
.withProtocol(.https)
97+
.withHeaders(.init(headers))
98+
.withBody(.data(urlRequest.httpBody))
99+
100+
return requestBuilder
101+
}
102+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
@_spi(InternalAmplifyConfiguration) import Amplify
10+
11+
public struct AWSAppSyncConfiguration {
12+
public let region: String
13+
public let endpoint: URL
14+
public let apiKey: String?
15+
16+
public init(with amplifyOutputs: AmplifyOutputs) throws {
17+
let resolvedConfiguration = try amplifyOutputs.resolveConfiguration()
18+
19+
guard let dataCategory = resolvedConfiguration.data else {
20+
throw ConfigurationError.invalidAmplifyOutputsFile(
21+
"Missing data category", "", nil)
22+
}
23+
24+
self.region = dataCategory.awsRegion
25+
guard let endpoint = URL(string: dataCategory.url) else {
26+
throw ConfigurationError.invalidAmplifyOutputsFile(
27+
"Missing region from data category", "", nil)
28+
}
29+
self.endpoint = endpoint
30+
self.apiKey = dataCategory.apiKey
31+
32+
}
33+
}

AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import Foundation
1313

1414
public class AmplifyAWSCredentialsProvider: AWSClientRuntime.CredentialsProviding {
1515

16+
public init() {
17+
}
18+
1619
public func getCredentials() async throws -> AWSClientRuntime.AWSCredentials {
1720
let authSession = try await Amplify.Auth.fetchAuthSession()
1821
if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider {

0 commit comments

Comments
 (0)