繁体   English   中英

将 Apollo iOS 客户端 GraphQL 查询变量和 url 记录到控制台?

[英]Log Apollo iOS Client GraphQL query variables and url to console?

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

我不知道如何让所有 Apollo url 调用打印到控制台,但通过扩展 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()

示例 output:

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 来获取相同的信息,这也将支持突变和订阅。

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

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

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

使用 Proxyman 的 GraphQL QueryName

根据Apollo iOS 客户端文档,可以在自定义拦截器提供程序中添加日志拦截器。

我使用来自 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)
}()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM