diff --git a/Tests/ApolloTests/RequestChainTests.swift b/Tests/ApolloTests/RequestChainTests.swift index 993148a19..d241b55d2 100644 --- a/Tests/ApolloTests/RequestChainTests.swift +++ b/Tests/ApolloTests/RequestChainTests.swift @@ -295,6 +295,56 @@ class RequestChainTests: XCTestCase { } } + func test__error__givenGraphqlError_withoutData_shouldReturnError() { + // given + let client = MockURLSessionClient( + response: .mock( + url: TestURL.mockServer.url, + statusCode: 200, + httpVersion: nil, + headerFields: nil + ), + data: """ + { + "errors": [{ + "message": "Bad request, could not start execution!" + }] + } + """.data(using: .utf8) + ) + + let interceptorProvider = DefaultInterceptorProvider(client: client, store: ApolloStore()) + let interceptors = interceptorProvider.interceptors(for: MockQuery.mock()) + let requestChain = InterceptorRequestChain(interceptors: interceptors) + + let expectation = expectation(description: "Response received") + + let request = JSONRequest( + operation: MockQuery(), + graphQLEndpoint: TestURL.mockServer.url, + clientName: "test-client", + clientVersion: "test-client-version" + ) + + // when + then + requestChain.kickoff(request: request) { result in + defer { + expectation.fulfill() + } + + switch (result) { + case let .success(data): + XCTAssertEqual(data.errors, [ + GraphQLError("Bad request, could not start execution!") + ]) + case let .failure(error): + XCTFail("Unexpected failure result - \(error)") + } + } + + wait(for: [expectation], timeout: 1) + } + // MARK: Multipart request tests struct RequestTrapInterceptor: ApolloInterceptor { diff --git a/apollo-ios/Sources/Apollo/CacheWriteInterceptor.swift b/apollo-ios/Sources/Apollo/CacheWriteInterceptor.swift index 63b0b4bd3..1eeea3ca8 100644 --- a/apollo-ios/Sources/Apollo/CacheWriteInterceptor.swift +++ b/apollo-ios/Sources/Apollo/CacheWriteInterceptor.swift @@ -7,17 +7,12 @@ import ApolloAPI public struct CacheWriteInterceptor: ApolloInterceptor { public enum CacheWriteError: Error, LocalizedError { - @available(*, deprecated, message: "Will be removed in a future version.") case noResponseToParse - case missingCacheRecords - public var errorDescription: String? { switch self { case .noResponseToParse: return "The Cache Write Interceptor was called before a response was received to be parsed. Double-check the order of your interceptors." - case .missingCacheRecords: - return "The Cache Write Interceptor cannot find any cache records. Double-check the order of your interceptors." } } } @@ -37,7 +32,11 @@ public struct CacheWriteInterceptor: ApolloInterceptor { request: HTTPRequest, response: HTTPResponse?, completion: @escaping (Result, any Error>) -> Void) { - + + guard !chain.isCancelled else { + return + } + guard request.cachePolicy != .fetchIgnoringCacheCompletely else { // If we're ignoring the cache completely, we're not writing to it. chain.proceedAsync( @@ -49,12 +48,9 @@ public struct CacheWriteInterceptor: ApolloInterceptor { return } - guard - let createdResponse = response, - let cacheRecords = createdResponse.cacheRecords - else { + guard let createdResponse = response else { chain.handleErrorAsync( - CacheWriteError.missingCacheRecords, + CacheWriteError.noResponseToParse, request: request, response: response, completion: completion @@ -62,12 +58,10 @@ public struct CacheWriteInterceptor: ApolloInterceptor { return } - guard !chain.isCancelled else { - return + if let cacheRecords = createdResponse.cacheRecords { + self.store.publish(records: cacheRecords, identifier: request.contextIdentifier) } - self.store.publish(records: cacheRecords, identifier: request.contextIdentifier) - chain.proceedAsync( request: request, response: createdResponse,