订阅

订阅

GraphQL支持订阅,允许客户端在服务器上的数据发生更改时立即进行更新。

Apollo iOS库主要通过ApolloWebSocket支持订阅的使用,这是一个可选的附加库,它使用流行的iOS WebSocket库Starscream来连接到GraphQL服务器。

通过代码生成还支持订阅:每当声明订阅字段时,都会生成符合GraphQLSubscription的操作,该操作允许传递订阅字段所接受的任何参数。

生成这些操作之后,可以使用支持订阅的网络传输使用ApolloClient实例进行订阅,并继续接收有关更改的更新,直到取消订阅。

支持订阅的传输类型

有两个不同的类符合ApolloWebSocket库中的网络传输协议:

WebSocketTransport通过一个web套接字发送所有操作。 SplitNetworkTransport挂载于WebSocketTransport实例和UploadingNetworkTransport实例(通常是HTTPNetworkTransport),以便创建单个网络传输,该传输可以使用http进行查询和转换,使用web sockets进行订阅。 通常,使用SplitNetworkTransport,因为这允许保留单个网络传输设置,并避免使用多个客户端对象的任何潜在问题。

import Foundation
import Apollo
import ApolloWebSocket

// MARK: - Singleton Wrapper

class Apollo {
  static let shared = Apollo() 
    
  /// A web socket transport to use for subscriptions  
  private lazy var webSocketTransport: WebSocketTransport = {
    let url = URL(string: "ws://localhost:8080/websocket")!
    let request = URLRequest(url: url)
    return WebSocketTransport(request: request)
  }()
  
  /// An HTTP transport to use for queries and mutations
  private lazy var httpTransport: HTTPNetworkTransport = {
    let url = URL(string: "http://localhost:8080/graphql")!
    return HTTPNetworkTransport(url: url)
  }()

  /// A split network transport to allow the use of both of the above 
  /// transports through a single `NetworkTransport` instance.
  private lazy var splitNetworkTransport = SplitNetworkTransport(
    httpNetworkTransport: self.httpTransport, 
    webSocketNetworkTransport: self.webSocketTransport
  )

  /// Create a client using the `SplitNetworkTransport`.
  private(set) lazy var client = ApolloClient(networkTransport: self.splitNetworkTransport)
}

class ReviewViewController: UIViewController {

  private var subscription: Cancellable?
  private var reviewList = [Review]()
  
  // Assume data source and delegate are hooked up in Interface Builder
  @IBOutlet private var reviewTableView: UITableView!
    
  override func viewDidLoad() {
    super.viewDidLoad()
    
    // Set the subscription variable up - be careful not to create a retain cycle!
    self.subscription = Apollo.shared.client
        .subscribe(subscription: ReviewAddedSubscription()) { [weak self] result in
          guard let self = self else {
            return 
          }
      
          switch result {
          case .success(let graphQLResult): 
            if let review = graphQLResult.data?.reviewAdded {
              // A review was added - append it to the list then reload the data.
              self.reviewList.append(review)
              self.reviewTableView.reloadData()
            } // else, something went wrong and you should check `graphQLResult.error` for problems
          case .failure(let error):
            // Not included here: Show some kind of alert
          }
    }
  }
  
  deinit {
    // Make sure the subscription is cancelled, if it exists, when this object is deallocated.
    self.subscription?.cancel()
  }
  
  // MARK: - Standard TableView Stuff
  
  func tableView(_ tableView: UITableView, 
                 numberOfRowsInSection section: Int) -> Int {
    return self.reviewList.count
  }
  
 func tableView(_ tableView: UITableView, 
                cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Assume `ReviewCell` is a cell for displaying reviews created elsewhere
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? ReviewCell else {
      return UITableViewCell()
    } 
    
    let review = self.reviewList[indexPath.row]
    
    cell.episode = review.episode
    cell.stars = review.stars
    cell.commentary = review.commentary
    
    return cell
  }
}

在标准的HTTP操作中,如果需要身份验证,通常会发送一个授权头和请求。但是,对于web套接字,由于需要持久连接,因此不能将其与每个有效负载一起发送。

对于web套接字,connectingPayload提供了那些通常作为请求头的一部分指定的参数。

import Foundation
import Apollo
import ApolloWebSocket

// MARK: - Singleton Wrapper

let magicToken = "So long and thanks for all the fish"

class Apollo {
  static let shared = Apollo()
    
  /// A web socket transport to use for subscriptions
  // This web socket will have to provide the connecting payload which
  // initializes the connection as an authorized channel.
  private lazy var webSocketTransport: WebSocketTransport = {
    let url = URL(string: "ws://localhost:8080/websocket")!
    let request = URLRequest(url: url)
    let authPayload = ["authToken": magicToken]
    return WebSocketTransport(request: request, connectingPayload: authPayload)
  }()
  
  /// An HTTP transport to use for queries and mutations.
  private lazy var httpTransport: HTTPNetworkTransport = {
    let url = URL(string: "http://localhost:8080/graphql")!
    return HTTPNetworkTransport(url: url)
  }()

  /// A split network transport to allow the use of both of the above 
  /// transports through a single `NetworkTransport` instance.
  private lazy var splitNetworkTransport = SplitNetworkTransport(
    httpNetworkTransport: self.httpTransport, 
    webSocketNetworkTransport: self.webSocketTransport
  )

  /// Create a client using the `SplitNetworkTransport`.
  private(set) lazy var client = ApolloClient(networkTransport: self.splitNetworkTransport)
}
原文地址:https://www.cnblogs.com/liuxiaokun/p/12676847.html