(Http)Interceptors with apollo subscription client

Hi,

I am using the Kotlin Apollo Client v3.0.0 (GitHub - apollographql/apollo-kotlin:  A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform.).

I really enjoy the possibility to add http interceptors like f.e. the brand new LoggingInterceptor available on v3.0.0 on my ApolloClient when I build one for queries and mutations.

I would like to setup interceptors like the LoggingInterceptor also for apollo clients I setup for subscriptions like this one:

  val subscriptionWsProtocol = SubscriptionWsProtocol.Factory(
  connectionPayload = {
      mapOf("token" to "a-token-here")
    }
  )

  val subscriptionNetworkTransport = WebSocketNetworkTransport.Builder()
    .serverUrl("https://my-url-here.com")
    .protocol(subscriptionWsProtocol)
    .reconnectWhen {
      // this is called when an error happens on the WebSocket
      it is ApolloWebSocketClosedException && it.code == 1001
    }

  val apolloSubscriptionClientBuilder = ApolloClient.Builder()
    .httpServerUrl("https://my-url-here.com")
    .subscriptionNetworkTransport(subscriptionNetworkTransport.build())

  // this has no effect when I set an HttpInterceptor like this
  apolloClientBuilder.addHttpInterceptor(LoggingInterceptor())
  
  val finalApolloClient = apolloSubscriptionClientBuilder.build()

Can you please tell me how to do that? Is that possible at the moment? When trying to add one with addHttpInterceptor this has no effect.

I am thankful for every suggestion, because I really have no idea anymore. I also browsed the apollo code in the IDE but did not find the way how to do it.

Hi :wave: Thanks for reaching out. As you found out, there is no WebSocket interceptor. I’m not sure how that would work because WebSockets are asynchrounous/multiplexed by default so it’s not a succession of requests that return a response.

If you don’t explicitely require the details of the WebSocket communication, you can setup a GraphQL interceptor with ApolloClient.Builder.addInterceptor(). This will intercept all GraphQL requests, including subscriptions.

If you specifically need a WebSocket interceptor, may I ask what the use case is? Is it for logging what’s happening on the network? Or something else?

Hi :wave: mbonnin,

thanks for answering and for the explanation :slightly_smiling_face:. Yes one purpose for the interceptor is Logging when establishing the WebSocket connection. I want to see all the network communication as logs in the console.

The LoggingInterceptor f.e. logs out very nicely the hole communication code, executed operation, send headers and so on. It would be nice to have the same logging also when establish a subscription connection. This can be done by implementing and adding a corresponding ApolloInterceptor to the build ApolloClient for subscriptions?

The other usecase is that I want to customize the standardly send X-APOLLO-OPERATION-NAME header and for this I also use an HttpInterceptor for queries and mutations. This header is probably also set by the apollo client when a subscription is established?

Thanks for the details.

For logging the WebSocket, you won’t be able to use ApolloInterceptor because ApolloInterceptor works at the GraphQL level so it will contain the parsed response but not the raw data transferred. There’s no builtin way to add logging as of now but if you open an issue on the repo, we’ll look into it.

As a workaround, you can use a proxy like Charles Proxy to log from outside your app. Or you can also copy/paste the DefaultWebSocketEngine and uncomment the println there.

For the X-APOLLO-OPERATION-NAME header, it doesn’t make a lot of sense with websockets. You can add headers to the initial WebSocket handshake. But subsequent subscriptions don’t really use HTTP so there’s no header per-se. You can check the protocol there: subscriptions-transport-ws/PROTOCOL.md at master · apollographql/subscriptions-transport-ws · GitHub

1 Like

Hi mbonnin :wave:, thanks for the reply and the explanations. That makes totally sense. Now I also have here a better understanding and my questions are answered.

1 Like

so what was your solution? Did you succeed to logging the subscription data?

Thanks in advance

I am interested for iOS

why don’t you people read the comments ? Martin said you can either use charles or copy paste the DefaultWebSocketEngine file - the latter is what we do to log it from inside.