From 306e627c71bc135ff0dfe92b016f96d9b572c2ce Mon Sep 17 00:00:00 2001 From: Benedikt Terhechte Date: Fri, 16 Dec 2022 09:15:08 +0100 Subject: [PATCH] save responses and subscriptions --- Sources/SwiftGraphQL/HTTP+WebSockets.swift | 31 +++++++++++++++++++- Sources/SwiftGraphQL/HTTP.swift | 33 ++++++++++++++++++---- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/Sources/SwiftGraphQL/HTTP+WebSockets.swift b/Sources/SwiftGraphQL/HTTP+WebSockets.swift index dc1d1061..32a21d27 100644 --- a/Sources/SwiftGraphQL/HTTP+WebSockets.swift +++ b/Sources/SwiftGraphQL/HTTP+WebSockets.swift @@ -101,7 +101,7 @@ public class GraphQLSocket { // log: OSLog.subscription, // type: .debug, (String(data: data, encoding: .utf8) ?? "Invalid .utf8") // ) - guard let message = try? JSONDecoder().decode(Message.self, from: data) else { + guard var message = try? JSONDecoder().decode(Message.self, from: data) else { os_log("Invalid JSON Payload", log: OSLog.subscription, type: .debug) return false } @@ -130,6 +130,7 @@ public class GraphQLSocket { self?.state = .running case .next, .error, .complete, .data: guard let id = message.id else { return false } + message.originalData = data self?.subscriptions[id]?(message) case .connection_terminate, .connection_error: self?.restart(errorHandler: errorHandler) @@ -220,6 +221,21 @@ public class GraphQLSocket { self?.complete(id: id) } + #if DEBUG + #if targetEnvironment(simulator) + let payload = selection.buildPayload(operationName: operationName) + + // Write the query. We also need the id, so we encode it into the variables + try? payload.query.write(toFile: "/tmp/query_\(id).graphql", atomically: true, encoding: .utf8) + // Write the variables + var copiedVariables = payload.variables + copiedVariables["gql-subscription-id"] = AnyCodable(stringLiteral: id) + if let variables = try? encoder.encode(copiedVariables) { + try? variables.write(to: URL(fileURLWithPath: "/tmp/query_variables_\(id).json")) + } + #endif + #endif + switch state { case .notRunning: if autoConnect { @@ -260,6 +276,17 @@ public class GraphQLSocket { switch message.type { case .next, .data: do { + if let originalData = message.originalData { + +#if DEBUG +#if targetEnvironment(simulator) + // write the response out. A given subscription can have multiple responses. + let debugTime = DispatchTime.now().uptimeNanoseconds + let url = URL(fileURLWithPath: "/tmp/subscription_response_\(id)_\(debugTime).json") + try? originalData.write(to: url) +#endif +#endif + } let result = try GraphQLResult(webSocketMessage: message, with: selection) eventHandler(.success(result)) } catch { @@ -339,6 +366,8 @@ public struct GraphQLSocketMessage: Codable { case pong } + public var originalData: Data? + public var type: MessageType public var id: String? /// Used for retreiving payload after decoding incomming message diff --git a/Sources/SwiftGraphQL/HTTP.swift b/Sources/SwiftGraphQL/HTTP.swift index cd090282..51f82372 100644 --- a/Sources/SwiftGraphQL/HTTP.swift +++ b/Sources/SwiftGraphQL/HTTP.swift @@ -89,17 +89,39 @@ private func send( return nil } + let debugTime = DispatchTime.now().uptimeNanoseconds + // Construct a GraphQL request. let request = createGraphQLRequest( selection: selection, operationName: operationName, url: url, headers: headers, - method: method + method: method, + debugTime: debugTime ) // Create a completion handler. func onComplete(data: Data?, response: URLResponse?, error: Error?) { + + // Save the response or the error, depending on what's available + #if DEBUG + #if targetEnvironment(simulator) + let fallback = "\(String(describing: response))".data(using: .utf8) ?? "{'error': 'Could not serialize response'}".data(using: .utf8)! + let responeData: Data + if let data = data { + responeData = data + } else if let error = error { + responeData = "{'error': '\(error.localizedDescription)'}".data(using: .utf8) + ?? fallback + } else { + responeData = fallback + } + let url = URL(fileURLWithPath: "/tmp/query_response_\(debugTime).json") + try? responeData.write(to: url) + #endif + #endif + /* Process the response. */ // Check for HTTP errors. if let error = error { @@ -197,7 +219,8 @@ private func createGraphQLRequest( operationName: String?, url: URL, headers: HttpHeaders, - method: HttpMethod + method: HttpMethod, + debugTime: UInt64 ) -> URLRequest where TypeLock: GraphQLOperation & Decodable { // Construct a request. var request = URLRequest(url: url) @@ -216,12 +239,10 @@ private func createGraphQLRequest( #if DEBUG #if targetEnvironment(simulator) // Write the query - let time = DispatchTime.now().uptimeNanoseconds - let filename = operationName ?? "\(time)" - try? payload.query.write(toFile: "/tmp/query_\(filename).graphql", atomically: true, encoding: .utf8) + try? payload.query.write(toFile: "/tmp/query_\(debugTime).graphql", atomically: true, encoding: .utf8) // Write the variables if let variables = try? encoder.encode(payload.variables) { - try? variables.write(to: URL(fileURLWithPath: "/tmp/query_variables_\(filename).json")) + try? variables.write(to: URL(fileURLWithPath: "/tmp/query_variables_\(debugTime).json")) } #endif #endif