diff --git a/Sources/Apollo/ApolloStore.swift b/Sources/Apollo/ApolloStore.swift index fd26ac0915..4a42462769 100644 --- a/Sources/Apollo/ApolloStore.swift +++ b/Sources/Apollo/ApolloStore.swift @@ -175,6 +175,7 @@ public final class ApolloStore { accumulator: zip(mapper, dependencyTracker)) }.map { (data: Query.Data, dependentKeys: Set) in GraphQLResult(data: data, + extensions: nil, errors: nil, source:.cache, dependentKeys: dependentKeys) diff --git a/Sources/Apollo/GraphQLResponse.swift b/Sources/Apollo/GraphQLResponse.swift index f5e4f60e65..49e360dd30 100644 --- a/Sources/Apollo/GraphQLResponse.swift +++ b/Sources/Apollo/GraphQLResponse.swift @@ -20,6 +20,8 @@ public final class GraphQLResponse { errors = nil } + let extensions = body["extensions"] as? JSONObject + if let dataEntry = body["data"] as? JSONObject { let executor = GraphQLExecutor { object, info in return .result(.success(object[info.responseKeyForField])) @@ -40,15 +42,17 @@ public final class GraphQLResponse { }.map { (data, records, dependentKeys) in ( GraphQLResult(data: data, - errors: errors, - source: .server, - dependentKeys: dependentKeys), + extensions: extensions, + errors: errors, + source: .server, + dependentKeys: dependentKeys), records ) } } else { return Promise(fulfilled: ( GraphQLResult(data: nil, + extensions: extensions, errors: errors, source: .server, dependentKeys: nil), @@ -67,6 +71,7 @@ public final class GraphQLResponse { func parseResultFast() throws -> GraphQLResult { let errors = self.parseErrorsOnlyFast() + let extensions = body["extensions"] as? JSONObject if let dataEntry = body["data"] as? JSONObject { let data = try decode(selectionSet: Data.self, @@ -74,11 +79,13 @@ public final class GraphQLResponse { variables: variables) return GraphQLResult(data: data, + extensions: extensions, errors: errors, source: .server, dependentKeys: nil) } else { return GraphQLResult(data: nil, + extensions: extensions, errors: errors, source: .server, dependentKeys: nil) diff --git a/Sources/Apollo/GraphQLResult.swift b/Sources/Apollo/GraphQLResult.swift index 6821d23094..0dd7d31afe 100644 --- a/Sources/Apollo/GraphQLResult.swift +++ b/Sources/Apollo/GraphQLResult.swift @@ -4,6 +4,8 @@ public struct GraphQLResult { public let data: Data? /// A list of errors, or `nil` if the operation completed without encountering any errors. public let errors: [GraphQLError]? + /// A dictionary which services can use however they see fit to provide additional information to clients. + public let extensions: [String: Any]? /// Represents source of data public enum Source { @@ -16,10 +18,12 @@ public struct GraphQLResult { let dependentKeys: Set? public init(data: Data?, + extensions: [String: Any]?, errors: [GraphQLError]?, source: Source, dependentKeys: Set?) { self.data = data + self.extensions = extensions self.errors = errors self.source = source self.dependentKeys = dependentKeys diff --git a/Tests/ApolloTests/ParseQueryResponseTests.swift b/Tests/ApolloTests/ParseQueryResponseTests.swift index 087d7ec9f2..7186cec2e2 100644 --- a/Tests/ApolloTests/ParseQueryResponseTests.swift +++ b/Tests/ApolloTests/ParseQueryResponseTests.swift @@ -314,6 +314,60 @@ class ParseQueryResponseTests: XCTestCase { } } + func testExtensionsEntryNotNullWhenProvidedInResponseAccompanyingDataEntry() throws { + let query = HumanQuery(id: "9999") + + let response = GraphQLResponse(operation: query, body: [ + "data": ["human": NSNull()], + "extensions": [:] + ]) + + let (result, _) = try response.parseResult().await() + + XCTAssertNotNil(result.extensions) + } + + func testExtensionsValuesWhenPopulatedInResponse() throws { + let query = HumanQuery(id: "9999") + + let response = GraphQLResponse(operation: query, body: [ + "data": ["human": NSNull()], + "extensions": ["parentKey": ["childKey": "someValue"]] + ]) + + let (result, _) = try response.parseResult().await() + let extensionsDictionary = result.extensions + let childDictionary = extensionsDictionary?["parentKey"] as? JSONObject + + XCTAssertNotNil(extensionsDictionary) + XCTAssertNotNil(childDictionary) + XCTAssertEqual(childDictionary, ["childKey": "someValue"]) + } + + func testExtensionsEntryNullWhenNotProvidedInResponse() throws { + let query = HumanQuery(id: "9999") + + let response = GraphQLResponse(operation: query, body: [ + "data": ["human": NSNull()] + ]) + + let (result, _) = try response.parseResult().await() + + XCTAssertNil(result.extensions) + } + + func testExtensionsEntryNotNullWhenDataEntryNotProvidedInResponse() throws { + let query = HumanQuery(id: "9999") + + let response = GraphQLResponse(operation: query, body: [ + "extensions": [:] + ]) + + let (result, _) = try response.parseResult().await() + + XCTAssertNotNil(result.extensions) + } + // MARK: Mutations func testCreateReviewForEpisode() throws {