From 4f7b1e5f51148ecaacf8f0e8b01add3d88732b4c Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Mon, 4 Nov 2024 10:18:57 -0800 Subject: [PATCH 1/3] Throw error if partial errors are detected --- Sources/DataConnectError.swift | 4 ++++ Sources/Internal/GrpcClient.swift | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/Sources/DataConnectError.swift b/Sources/DataConnectError.swift index c6e299f..f4dfe97 100644 --- a/Sources/DataConnectError.swift +++ b/Sources/DataConnectError.swift @@ -34,4 +34,8 @@ public enum DataConnectError: Error { /// timestamp components specified to initialize Timestamp are invalid case invalidTimestampFormat + + /// generic operation execution error + case operationExecutionFailed + } diff --git a/Sources/Internal/GrpcClient.swift b/Sources/Internal/GrpcClient.swift index 5f41f24..544f255 100644 --- a/Sources/Internal/GrpcClient.swift +++ b/Sources/Internal/GrpcClient.swift @@ -148,7 +148,12 @@ actor GrpcClient: CustomStringConvertible { let resultsString = try results.jsonString() DataConnectLogger .debug("executeQuery() receives response: \(resultsString, privacy: .private).") + // Not doing error decoding here + guard results.errors.isEmpty else { + throw DataConnectError.operationExecutionFailed + } + if let decodedResults = try codec.decode(result: results.data, asType: resultType) { return OperationResult(data: decodedResults) } else { @@ -191,6 +196,11 @@ actor GrpcClient: CustomStringConvertible { let resultsString = try results.jsonString() DataConnectLogger .debug("executeMutation() receives response: \(resultsString, privacy: .private).") + + guard results.errors.isEmpty else { + throw DataConnectError.operationExecutionFailed + } + if let decodedResults = try codec.decode(result: results.data, asType: resultType) { return OperationResult(data: decodedResults) } else { From 6ddf092f4b644822e325d3bede7eea3750b1de71 Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Mon, 4 Nov 2024 10:20:49 -0800 Subject: [PATCH 2/3] fix style issue --- Sources/DataConnectError.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/DataConnectError.swift b/Sources/DataConnectError.swift index f4dfe97..3b14d57 100644 --- a/Sources/DataConnectError.swift +++ b/Sources/DataConnectError.swift @@ -37,5 +37,4 @@ public enum DataConnectError: Error { /// generic operation execution error case operationExecutionFailed - } From 46a4acd7f98d3eb193d4879226e78741a8066f51 Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Mon, 4 Nov 2024 11:51:06 -0800 Subject: [PATCH 3/3] Denver feedback: Include error messages in the error code. --- Sources/DataConnectError.swift | 2 +- Sources/Internal/GrpcClient.swift | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Sources/DataConnectError.swift b/Sources/DataConnectError.swift index 3b14d57..b12b49c 100644 --- a/Sources/DataConnectError.swift +++ b/Sources/DataConnectError.swift @@ -36,5 +36,5 @@ public enum DataConnectError: Error { case invalidTimestampFormat /// generic operation execution error - case operationExecutionFailed + case operationExecutionFailed(messages: String?) } diff --git a/Sources/Internal/GrpcClient.swift b/Sources/Internal/GrpcClient.swift index 544f255..29b0cd3 100644 --- a/Sources/Internal/GrpcClient.swift +++ b/Sources/Internal/GrpcClient.swift @@ -27,6 +27,7 @@ import SwiftProtobuf @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) typealias FirebaseDataConnectAsyncClient = Google_Firebase_Dataconnect_V1beta_ConnectorServiceAsyncClient +typealias FirebaseDataConnectGraphqlError = Google_Firebase_Dataconnect_V1beta_GraphqlError @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) actor GrpcClient: CustomStringConvertible { @@ -151,7 +152,8 @@ actor GrpcClient: CustomStringConvertible { // Not doing error decoding here guard results.errors.isEmpty else { - throw DataConnectError.operationExecutionFailed + throw DataConnectError + .operationExecutionFailed(messages: createErrorJson(errors: results.errors)) } if let decodedResults = try codec.decode(result: results.data, asType: resultType) { @@ -198,7 +200,8 @@ actor GrpcClient: CustomStringConvertible { .debug("executeMutation() receives response: \(resultsString, privacy: .private).") guard results.errors.isEmpty else { - throw DataConnectError.operationExecutionFailed + throw DataConnectError + .operationExecutionFailed(messages: createErrorJson(errors: results.errors)) } if let decodedResults = try codec.decode(result: results.data, asType: resultType) { @@ -216,6 +219,22 @@ actor GrpcClient: CustomStringConvertible { } } + private func createErrorJson(errors: [FirebaseDataConnectGraphqlError]) -> String? { + var errorMessages = [String]() + for err in errors { + errorMessages.append(err.message) + } + + do { + let jsonEncoder = JSONEncoder() + let jsonData = try jsonEncoder.encode(errorMessages) + return String(data: jsonData, encoding: .utf8) + } catch { + DataConnectLogger.error("Error encoding partial error list") + return nil + } + } + func createCallOptions() async -> CallOptions { var headers = HPACKHeaders()