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

Posted

技术标签:

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

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

【问题讨论】:

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

【讨论】:

有一个简单的方法来获取QueryName:docs.proxyman.io/advanced-features/…

以上是关于将 Apollo iOS Client GraphQL 查询变量和 url 记录到控制台?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Apollo Client for iOS 读取结果

在 GraphQL Apollo Client iOS 中模拟 JSON 数据解析

是否可以将服务注入 apollo-client 的中间件?

如何将 localStorage 与 apollo-client 和 reactjs 一起使用?

突变后 React Apollo 客户端道具 refetchQueries

如何使用 Apollo Client 虚拟字段