Subscriptions


Subscriptions are long-lived GraphQL read operations that can update their response over time, enabling clients to receive new data as it becomes available.

Apollo iOS supports subscriptions over the following protocols:

You must use whichever protocol is supported by your GraphQL endpoint.

Enabling support

To support GraphQL subscriptions, you need to initialize your ApolloClient instance with a NetworkTransport that supports subscriptions. See below for applicable classes for each subscription protocol.

WebSocket

To use Apollo iOS with WebSocket-based subscriptions, you need to install the optional ApolloWebSocket library. This library includes two classes that conform to the NetworkTransport protocol:

SplitNetworkTransport is recommended for most use cases, because it enables you to retain a single NetworkTransport setup that avoids issues caused by using multiple client objects.

Here's an example of setting up an ApolloClient that uses a SplitNetworkTransport to support all operation types:

Click to expand
Swift
1/// A common store to use for `httpTransport` and `webSocketTransport`.
2let store = ApolloStore()
3
4/// A web socket transport to use for subscriptions
5let webSocketTransport: WebSocketTransport = {
6  let url = URL(string: "ws://localhost:8080/websocket")!
7  let webSocketClient = WebSocket(url: url, protocol: .graphql_transport_ws)
8  return WebSocketTransport(websocket: webSocketClient)
9}()
10
11/// An HTTP transport to use for queries and mutations
12let httpTransport: RequestChainNetworkTransport = {
13  let url = URL(string: "http://localhost:8080/graphql")!
14  return RequestChainNetworkTransport(interceptorProvider: DefaultInterceptorProvider(store: store), endpointURL: url)
15}()
16
17/// A split network transport to allow the use of both of the above
18/// transports through a single `NetworkTransport` instance.
19let splitNetworkTransport = SplitNetworkTransport(
20  uploadingNetworkTransport: httpTransport,
21  webSocketNetworkTransport: webSocketTransport
22)
23
24/// Create a client using the `SplitNetworkTransport`.
25let client = ApolloClient(networkTransport: splitNetworkTransport, store: store)

WebSocket subprotocols

Apollo iOS supports the following WebSocket subprotocols for subscriptions:

Note: These protocols are not cross-compatible. You need to use whichever protocol is supported by your GraphQL endpoint. All WebSocket initializers enable you to specify which protocol to use (expand the code block above for an example).

Providing authorization tokens

In a standard HTTP operation, if authentication is necessary an Authorization header is often sent with requests. However, with WebSocket, this can't be sent with every payload because a persistent connection is required.

For WebSocket, the connectingPayload provides the parameters you would typically specify in your request headers.

Note that this must be set when the WebSocketTransport is created. If you need to update the connectingPayload, you need to recreate the client using a new webSocketTransport.

Swift
1let webSocketTransport: WebSocketTransport = {
2  let url = URL(string: "ws://localhost:8080/websocket")!
3  let webSocketClient = WebSocket(url: url, protocol: .graphql_transport_ws)
4  let authPayload: JSONEncodableDictionary = ["authToken": myAuthToken]
5  let config = WebSocketTransport.Configuration(connectingPayload: authPayload)
6  return WebSocketTransport(websocket: webSocketClient, config: config)
7}()

HTTP

The default NetworkTransport for Apollo iOS is the RequestChainNetworkTransport. In Apollo iOS 1.1.0 and later, this transport supports subscriptions over HTTP, with no additional configuration required.

See the instructions for creating a client.

Generating and executing

Apollo iOS supports subscriptions via code generation. Similar to queries, subscriptions are represented by instances of generated classes, conforming to the GraphQLSubscription protocol.

GraphQL
ReviewAddedSubscription.graphql
1subscription ReviewAdded {
2  reviewAdded {
3    id
4    stars
5  }
6}

After you generate these classes, you can execute subscriptions using ApolloClient.subscribe(subscription:) with a subscription-supporting NetworkTransport. If you do, your client continues to receive updated data until the subscription is canceled.

Swift
1let subscription = client.subscribe(subscription: ReviewAddedSubscription()) { result in
2  guard let data = try? result.get().data else { return }
3  print(data.reviews.map { $0.stars })
4}

Note: GraphQL subscriptions are distinct from watching queries. A query watcher is only updated when new data is written to the local cache (usually by another network operation). A GraphQL subscription is a long-lived request that might receive updated data from the server continually.

Canceling a subscription

It's important to cancel a subscription connection whenever you're done with it. As long as a subscription is active, it maintains a connection to the server, and its resultHandler completion block is retained. This can create memory leaks and reduce your application's performance.

When you call ApolloClient.subscribe(subscription:) an opaque Cancellable is returned. You can cancel the subscription by calling cancel() on the returned Cancellable. This terminates the connection to the server and releases the resultHandler completion block.

A subscription's cancellation object does not cancel itself when it's deallocated! Make sure to cancel() it yourself. A class can ensure any subscriptions it manages are canceled when it's released by using its deinitializer:

Swift
1class ReviewViewController {
2
3  let client: ApolloClient!
4  private var subscription: Cancellable?
5
6  func subscribeToReviews() {
7    // Keep a reference to the subscription's cancellation object.
8    self.subscription = client.subscribe(subscription: ReviewAddedSubscription()) { [weak self] result in
9      // Handle each update from the subscription.
10    }
11  }
12
13  deinit {
14    // Make sure the subscription is cancelled, if it exists, when this object is deallocated.
15    self.subscription?.cancel()
16  }
17}
Feedback

Edit on GitHub

Forums