Skip to content

Commit

Permalink
fix(API): pass authMode used for lazy loading functionality (#3690)
Browse files Browse the repository at this point in the history
* fix(API): pass authMode used for lazy loading functionality

* revert GraphQLFilter change
  • Loading branch information
lawmicha authored May 17, 2024
1 parent d6d5a23 commit 4156bfb
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Foundation
import Amplify
import AWSPluginsCore

/// This decoder is registered and used to detect various data payloads objects to store
/// inside an AppSyncListProvider when decoding to the Lazy `List` type as a "not yet loaded" List. If the data payload
Expand All @@ -18,6 +19,7 @@ public struct AppSyncListDecoder: ModelListDecoder {
let appSyncAssociatedIdentifiers: [String]
let appSyncAssociatedFields: [String]
let apiName: String?
let authMode: AWSAuthorizationType?
}

/// Used by the custom decoder implemented in the `List` type to detect if the payload can be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ public struct AppSyncListPayload: Codable {

let graphQLData: JSONValue
let apiName: String?
let authMode: AWSAuthorizationType?

public init(graphQLData: JSONValue,
apiName: String?,
authMode: AWSAuthorizationType?,
variables: [String: JSONValue]?) {
self.apiName = apiName
self.authMode = authMode
self.variables = variables
self.graphQLData = graphQLData
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public class AppSyncListProvider<Element: Model>: ModelListProvider {
/// The API friendly name used to reference the API to call
let apiName: String?

/// The auth mode used for this API call
let authMode: AWSAuthorizationType?

/// The limit for each page size
var limit: Int? = 1_000

Expand Down Expand Up @@ -42,7 +45,8 @@ public class AppSyncListProvider<Element: Model>: ModelListProvider {
convenience init(payload: AppSyncListPayload) throws {
let listResponse = try AppSyncListResponse.initWithMetadata(type: Element.self,
graphQLData: payload.graphQLData,
apiName: payload.apiName)
apiName: payload.apiName,
authMode: payload.authMode)

self.init(elements: listResponse.items,
nextToken: listResponse.nextToken,
Expand All @@ -59,27 +63,34 @@ public class AppSyncListProvider<Element: Model>: ModelListProvider {
convenience init(metadata: AppSyncListDecoder.Metadata) {
self.init(associatedIdentifiers: metadata.appSyncAssociatedIdentifiers,
associatedFields: metadata.appSyncAssociatedFields,
apiName: metadata.apiName)
apiName: metadata.apiName,
authMode: metadata.authMode)
}

// Internal initializer for testing
init(elements: [Element],
nextToken: String? = nil,
apiName: String? = nil,
authMode: AWSAuthorizationType? = nil,
limit: Int? = nil,
filter: [String: Any]? = nil) {
self.loadedState = .loaded(elements: elements,
nextToken: nextToken,
filter: filter)
self.apiName = apiName
self.authMode = authMode
self.limit = limit
}

// Internal initializer for testing
init(associatedIdentifiers: [String], associatedFields: [String], apiName: String? = nil) {
init(associatedIdentifiers: [String],
associatedFields: [String],
apiName: String? = nil,
authMode: AWSAuthorizationType? = nil) {
self.loadedState = .notLoaded(associatedIdentifiers: associatedIdentifiers,
associatedFields: associatedFields)
self.apiName = apiName
self.authMode = authMode
}

// MARK: APIs
Expand Down Expand Up @@ -128,14 +139,16 @@ public class AppSyncListProvider<Element: Model>: ModelListProvider {
modelSchema: Element.schema,
filter: filter,
limit: limit,
apiName: apiName)
apiName: apiName,
authMode: authMode)
do {
let graphQLResponse = try await Amplify.API.query(request: request)
switch graphQLResponse {
case .success(let graphQLData):
guard let listResponse = try? AppSyncListResponse.initWithMetadata(type: Element.self,
graphQLData: graphQLData,
apiName: self.apiName) else {
apiName: self.apiName,
authMode: self.authMode) else {
throw CoreError.listOperation("""
The AppSync response return successfully, but could not decode to
AWSAppSyncListResponse from: \(graphQLData)
Expand Down Expand Up @@ -196,7 +209,8 @@ public class AppSyncListProvider<Element: Model>: ModelListProvider {
filter: filter,
limit: limit,
nextToken: nextToken,
apiName: apiName)
apiName: apiName,
authMode: authMode)
do {
let graphQLResponse = try await Amplify.API.query(request: request)
switch graphQLResponse {
Expand Down Expand Up @@ -225,7 +239,8 @@ public class AppSyncListProvider<Element: Model>: ModelListProvider {
let metadata = AppSyncListDecoder.Metadata.init(
appSyncAssociatedIdentifiers: associatedIdentifiers,
appSyncAssociatedFields: associatedFields,
apiName: apiName)
apiName: apiName,
authMode: authMode)
var container = encoder.singleValueContainer()
try container.encode(metadata)
case .loaded(let elements, _, _):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Amplify
import Foundation
import AWSPluginsCore

/// Resembles the AppSync's GraphQL response for a list operation.
struct AppSyncListResponse<Element: Model>: Codable {
Expand All @@ -25,10 +26,14 @@ extension AppSyncListResponse {
/// model metadata on its array associations.
static func initWithMetadata(type: Element.Type,
graphQLData: JSONValue,
apiName: String?) throws -> AppSyncListResponse<Element> {
apiName: String?,
authMode: AWSAuthorizationType?) throws -> AppSyncListResponse<Element> {
var elements = [Element]()
if case let .array(jsonArray) = graphQLData["items"] {
let jsonArrayWithMetadata = AppSyncModelMetadataUtils.addMetadata(toModelArray: jsonArray, apiName: apiName)
let jsonArrayWithMetadata = AppSyncModelMetadataUtils.addMetadata(
toModelArray: jsonArray,
apiName: apiName,
authMode: authMode)

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = ModelDateFormatting.encodingStrategy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Foundation
import Amplify
import AWSPluginsCore

/// This decoder is registered and used to detect various data payloads to store
/// inside an `AppSyncModelProvider` when decoding to the `LazyReference` as a "not yet loaded" Reference. If the data payload
Expand All @@ -17,11 +18,16 @@ public struct AppSyncModelDecoder: ModelProviderDecoder {
struct Metadata: Codable {
let identifiers: [LazyReferenceIdentifier]
let apiName: String?
let authMode: AWSAuthorizationType?
let source: String

init(identifiers: [LazyReferenceIdentifier], apiName: String?, source: String = ModelProviderRegistry.DecoderSource.appSync) {
init(identifiers: [LazyReferenceIdentifier],
apiName: String?,
authMode: AWSAuthorizationType?,
source: String = ModelProviderRegistry.DecoderSource.appSync) {
self.identifiers = identifiers
self.apiName = apiName
self.authMode = authMode
self.source = source
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Amplify
import Foundation
import AWSPluginsCore

/// Holds the methods to traverse and maniupulate the response data object by injecting
public struct AppSyncModelMetadataUtils {
Expand All @@ -25,15 +26,17 @@ public struct AppSyncModelMetadataUtils {
}

static func addMetadata(toModelArray graphQLDataArray: [JSONValue],
apiName: String?) -> [JSONValue] {
apiName: String?,
authMode: AWSAuthorizationType?) -> [JSONValue] {
return graphQLDataArray.map { (graphQLData) -> JSONValue in
addMetadata(toModel: graphQLData, apiName: apiName)
addMetadata(toModel: graphQLData, apiName: apiName, authMode: authMode)
}
}

static func addMetadata(
toModel graphQLData: JSONValue,
apiName: String?,
authMode: AWSAuthorizationType?,
source: String = ModelProviderRegistry.DecoderSource.appSync) -> JSONValue {

guard case var .object(modelJSON) = graphQLData else {
Expand Down Expand Up @@ -89,6 +92,7 @@ public struct AppSyncModelMetadataUtils {
if let modelIdentifierMetadata = createModelIdentifierMetadata(associatedModelType,
modelObject: modelObject,
apiName: apiName,
authMode: authMode,
source: source) {
if let serializedMetadata = try? encoder.encode(modelIdentifierMetadata),
let metadataJSON = try? decoder.decode(JSONValue.self, from: serializedMetadata) {
Expand All @@ -104,7 +108,9 @@ public struct AppSyncModelMetadataUtils {
// add metadata to its fields, to create not loaded LazyReference objects
// only if the model type allowsfor lazy loading functionality
else if associatedModelType.rootPath != nil {
let nestedModelWithMetadata = addMetadata(toModel: nestedModelJSON, apiName: apiName)
let nestedModelWithMetadata = addMetadata(toModel: nestedModelJSON,
apiName: apiName,
authMode: authMode)
modelJSON.updateValue(nestedModelWithMetadata, forKey: modelField.name)
}
// otherwise do nothing to the data.
Expand All @@ -120,7 +126,8 @@ public struct AppSyncModelMetadataUtils {
if modelJSON[modelField.name] == nil {
let appSyncModelMetadata = AppSyncListDecoder.Metadata(appSyncAssociatedIdentifiers: identifiers,
appSyncAssociatedFields: modelField.associatedFieldNames,
apiName: apiName)
apiName: apiName,
authMode: authMode)
if let serializedMetadata = try? encoder.encode(appSyncModelMetadata),
let metadataJSON = try? decoder.decode(JSONValue.self, from: serializedMetadata) {
log.verbose("Adding [\(modelField.name): \(metadataJSON)]")
Expand All @@ -141,13 +148,16 @@ public struct AppSyncModelMetadataUtils {
associatedModelType.rootPath != nil {

for (index, item) in graphQLDataArray.enumerated() {
let modelJSON = AppSyncModelMetadataUtils.addMetadata(toModel: item, apiName: apiName)
let modelJSON = AppSyncModelMetadataUtils.addMetadata(toModel: item,
apiName: apiName,
authMode: authMode)
graphQLDataArray[index] = modelJSON
}

graphQLDataObject["items"] = JSONValue.array(graphQLDataArray)
let payload = AppSyncListPayload(graphQLData: JSONValue.object(graphQLDataObject),
apiName: apiName,
authMode: authMode,
variables: nil)

if let serializedPayload = try? encoder.encode(payload),
Expand All @@ -171,6 +181,7 @@ public struct AppSyncModelMetadataUtils {
static func createModelIdentifierMetadata(_ associatedModel: Model.Type,
modelObject: [String: JSONValue],
apiName: String?,
authMode: AWSAuthorizationType?,
source: String) -> AppSyncModelDecoder.Metadata? {
let primarykeys = associatedModel.schema.primaryKey
var identifiers = [LazyReferenceIdentifier]()
Expand All @@ -188,6 +199,7 @@ public struct AppSyncModelMetadataUtils {
return AppSyncModelDecoder.Metadata(
identifiers: identifiers,
apiName: apiName,
authMode: authMode,
source: source)
} else {
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import AWSPluginsCore
public class AppSyncModelProvider<ModelType: Model>: ModelProvider {

let apiName: String?
let authMode: AWSAuthorizationType?
let source: String
var loadedState: ModelProviderState<ModelType>

Expand All @@ -20,12 +21,14 @@ public class AppSyncModelProvider<ModelType: Model>: ModelProvider {
self.loadedState = .notLoaded(identifiers: metadata.identifiers)
self.apiName = metadata.apiName
self.source = metadata.source
self.authMode = metadata.authMode
}

// Creates a "loaded" provider
init(model: ModelType?) {
self.loadedState = .loaded(model: model)
self.apiName = nil
self.authMode = nil
self.source = ModelProviderRegistry.DecoderSource.appSync
}

Expand All @@ -41,7 +44,8 @@ public class AppSyncModelProvider<ModelType: Model>: ModelProvider {
}
let request = GraphQLRequest<ModelType?>.getRequest(ModelType.self,
byIdentifiers: identifiers,
apiName: apiName)
apiName: apiName,
authMode: authMode)
log.verbose("Loading \(ModelType.modelName) with \(identifiers)")
let graphQLResponse = try await Amplify.API.query(request: request)
switch graphQLResponse {
Expand All @@ -67,6 +71,7 @@ public class AppSyncModelProvider<ModelType: Model>: ModelProvider {
let metadata = AppSyncModelDecoder.Metadata(
identifiers: identifiers ?? [],
apiName: apiName,
authMode: authMode,
source: source)
try metadata.encode(to: encoder)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,26 @@ extension GraphQLResponseDecoder {
modelJSON = AppSyncModelMetadataUtils.addMetadata(
toModel: item,
apiName: request.apiName,
authMode: request.authMode as? AWSAuthorizationType,
source: ModelProviderRegistry.DecoderSource.dataStore)
} else {
modelJSON = AppSyncModelMetadataUtils.addMetadata(
toModel: item,
apiName: request.apiName)
apiName: request.apiName,
authMode: request.authMode as? AWSAuthorizationType)
}
graphQLDataArray[index] = modelJSON
}
graphQLDataObject["items"] = JSONValue.array(graphQLDataArray)
let payload = AppSyncListPayload(graphQLData: JSONValue.object(graphQLDataObject),
apiName: request.apiName,
authMode: request.authMode as? AWSAuthorizationType,
variables: try getVariablesJSON())
serializedJSON = try encoder.encode(payload)
} else if AppSyncModelMetadataUtils.shouldAddMetadata(toModel: graphQLData) { // 4
let modelJSON = AppSyncModelMetadataUtils.addMetadata(toModel: graphQLData,
apiName: request.apiName)
apiName: request.apiName,
authMode: request.authMode as? AWSAuthorizationType)
serializedJSON = try encoder.encode(modelJSON)
} else { // 5
serializedJSON = try encoder.encode(graphQLData)
Expand Down
Loading

0 comments on commit 4156bfb

Please sign in to comment.