I’m using subscriptions with AppSync, so i need to override the requestBodyCreator
parameters to make it work with AppSync.
AppSync’s server protocol is graphql-ws
and the payload using Amazon Cognito user pools is the following:
{
"id": "subscriptionId",
"type": "start",
"payload":
{
"data":
{
"query": "query string",
"variables": "variables"
},
"extensions":
{
"authorization":
{
"host": "host",
"Authorization": "accessToken"
}
}
}
}
This is not a problem on the first launch when i create the webSocketTransport
passing my custom AppSyncRequestBodyCreator
with a valid access token but when I put my app in the background and bring it to the foreground after an hour (the token has expired), the WebSocket disconnects (didDisconnectWithError
and reconnects (webSocketTransportDidReconnect
) , but I no longer receive updates from the subscriptions.
By logging webSocketTransport.subscriptions
, the subscriptions still appear to be active, but with an expired token.
Subscriptions ["1": "{\"id\":\"1\",\"payload\":{\"data\":\"{\\n \\\"query\\\" : \\\"subscription *** } }\\\"\\n}\",\"extensions\":{\"authorization\":{\"Authorization\":\"**** expired token",\"host\":\"***"}},\"operationName\":\"onCalendarChangedSubscription\"},\"type\":\"start\"}", "2": "{\"id\":\"2\",\"payload\":{\"data\":\"{\\n \\\"query\\\" : \\\"subscription OnSensorSyncSubscription { *** } }\\\"\\n}\",\"extensions\":{\"authorization\":{\"Authorization\":\"*** expired token",\"host\":\"**\"}},\"operationName\":\"OnSensorSyncSubscription\"},\"type\":\"start\"}"]
I think the problem is that on reconnection, the subscription start fails because the token has expired.
When the WebSocket disconnects, I call the updateHeaderValues
and updateConnectingPayload
methods, passing the updated token. (I doubt that the second method, updateConnectingPayload, is necessary, as the situation does not change.)
extension ApolloClientService: WebSocketTransportDelegate {
func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) {
logger.info("WebSocket connected", subsystem: Self.tag)
}
func webSocketTransportDidReconnect(_ webSocketTransport: WebSocketTransport) {
logger.info("WebSocket reconnected", subsystem: Self.tag)
printSubscriptions(webSocketTransport)
}
func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error: (any Error)?) {
Task {
let accessToken = try await authTokenDataSource.fetchAccessToken()
webSocketTransport.updateHeaderValues(["Authorization": accessToken], reconnectIfConnected: true)
webSocketTransport.updateConnectingPayload(buildAuthenticationPayload(), reconnectIfConnected: true)
printSubscriptions(webSocketTransport)
}
}
private func printSubscriptions(_ webSocketTransport: WebSocketTransport) {
if let subscriptions = webSocketTransport.getProperty(name: "subscriptions") as? [String: String] {
logger.trace("Subscriptions \(subscriptions.count)", subsystem: Self.tag)
logger.trace("Subscriptions \(subscriptions)", subsystem: Self.tag)
}
}
}
I need a way to update the Request body creator upon reconnection, but I can’t find a way to do it. Or any other strategy to make the subscription work again.
Have you any suggestion?