【问题标题】:Log Apollo iOS Client GraphQL query variables and url to console?将 Apollo iOS Client GraphQL 查询变量和 url 记录到控制台?
【发布时间】:2021-04-24 02:57:10
【问题描述】:

我想在调用查询时将我的 Apollo iOS 客户端 GraphQL 查询的 url 打印到 Xcode 控制台。

【问题讨论】:

    标签: ios swift graphql apollo


    【解决方案1】:

    您无需编写 swift 代码即可提取 QueryName。

    使用 Proxyman,例如 Charles Proxy。默认情况下,它将在列上显示 QueryName。

    参考:https://docs.proxyman.io/advanced-features/graphql

    【讨论】:

      【解决方案2】:

      根据Apollo iOS Client docs,可以在自定义拦截器提供程序中添加日志拦截器。

      我使用来自 DefaultInterceptorProvider 的代码创建了一个自定义拦截器提供程序,并包含了日志拦截器。

      import Apollo    
      
      class InterceptorProviderWithLogging: InterceptorProvider {
      
        private let client: URLSessionClient
        private let store: ApolloStore
        private let shouldInvalidateClientOnDeinit: Bool
      
        public init(client: URLSessionClient = URLSessionClient(),
                shouldInvalidateClientOnDeinit: Bool = true,
                store: ApolloStore) {
          self.client = client
          self.shouldInvalidateClientOnDeinit = shouldInvalidateClientOnDeinit
          self.store = store
        }
      
        deinit {
          if self.shouldInvalidateClientOnDeinit {
            self.client.invalidate()
          }
        }
      
        open func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
          return [
            MaxRetryInterceptor(),
            CacheReadInterceptor(store: self.store),
            RequestLoggingInterceptor(),        // added logging interceptor
            NetworkFetchInterceptor(client: self.client),
            ResponseCodeInterceptor(),
            JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject),
            AutomaticPersistedQueryInterceptor(),
            CacheWriteInterceptor(store: self.store),
          ]
        }
      
        open func additionalErrorInterceptor<Operation: GraphQLOperation>(for operation: Operation) -> ApolloErrorInterceptor? {
          return nil
        }
      }
      
      class RequestLoggingInterceptor: ApolloInterceptor {
      
        func interceptAsync<Operation: GraphQLOperation>(
          chain: RequestChain,
          request: HTTPRequest<Operation>,
          response: HTTPResponse<Operation>?,
          completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
                      
          if let url = try? request.toURLRequest().url?.absoluteString.removingPercentEncoding {
              if let variables = request.operation.variables {
                  print("\(request.operation.operationName) parameters: \(variables) \(url)")
              } else {
                  print("\(request.operation.operationName) \(url)")
              }
          }
          
          chain.proceedAsync(request: request, response: response, completion: completion)
        }
      }
      

      我在请求链网络传输中使用自定义拦截器提供程序。

      private(set) lazy var apolloClient: ApolloClient = {
      
        let store = ApolloStore()
        let interceptorProvider = InterceptorProviderWithLogging(store: store)
      
        let requestChainTransport = RequestChainNetworkTransport(
          interceptorProvider: interceptorProvider,
          endpointURL: url,
          additionalHeaders: [:],
          autoPersistQueries: false,
          requestBodyCreator: ApolloRequestBodyCreator(),
          useGETForQueries: true,
          useGETForPersistedQueryRetry: false
        )
      
        return ApolloClient(networkTransport: requestChainTransport, store: store)
      }()
      

      【讨论】:

        【解决方案3】:

        扩展 GraphQLQuery 提供对操作名称、操作 ID 和变量的访问,这些可用于构建 url。我还打印出查询的操作名称和变量。

        extension GraphQLQuery {
        
            func printInfo() {
            
                if let variables = self.variables?.JSONString {
                
                    let cleanedVariables = variables.replacingOccurrences(of: "\\", with: "")
                    print("GraphQL Query: \(self.operationName) \(variables))")
                
                    if let operationID = self.operationIdentifier {
                                    
                        let url = "\(GraphQLClient.shared.url)?extensions={\"persistedQuery\":{\"sha256Hash\":\"\(operationID)\",\"version\":1}}&id=\(operationID)&operationName=\(self.operationName)&variables=\(cleanedVariables)"
                        print("GraphQL URL", url)
                    }
                
                } else {
                    print("GraphQL Query: \(self.operationName)")
        
                    if let operationID = self.operationIdentifier {
                                    
                        let url = "\(GraphQLClient.shared.url)?extensions={\"persistedQuery\":{\"sha256Hash\":\"\(operationID)\",\"version\":1}}&id=\(operationID)&operationName=\(self.operationName)"
                        print("GraphQL URL", url)
                    }
                }
            }
        }
        

        用法:

        let standingsQuery = GetStandingsForSportQuery(sportID: sportIDInt, season: season)
        standingsQuery.printInfo()
        

        示例输出:

        GraphQL Query: getStandingsForSport {"sportID":7,"season":"2020"})
        GraphQL URL: https://api.company.com/graphql?extensions={"persistedQuery":{"sha256Hash":"932b414fdadb641f95659d6c61aa29d6d6b0ccf1fa704a0ace751187b90b8cac","version":1}}&id=932b414fdadb641f95659d6c61aa29d6d6b0ccf1fa704a0ace751187b90b8cac&operationName=getStandingsForSport&variables={"sportID":1,"season":"2020"}
        

        此示例中的 url 格式可能不是典型的,因为我们使用的是持久化查询。我使用 Charles 代理查看发送的实际 url,所以我知道格式。

        您还可以扩展 GraphQLOperation 而不是 GraphQLQuery 来获取相同的信息,这也将支持突变和订阅。

        【讨论】:

        猜你喜欢
        • 2019-06-13
        • 2018-03-02
        • 1970-01-01
        • 2018-02-10
        • 2020-04-06
        • 2020-11-08
        • 2019-03-13
        • 2018-11-06
        • 2019-07-22
        相关资源
        最近更新 更多