spring-projects / spring-graphql

Spring Integration for GraphQL
https://spring.io/projects/spring-graphql
Apache License 2.0
1.5k stars 297 forks source link

Closing the websocket connection if the type is not supported #965

Closed mehdizebhi closed 2 months ago

mehdizebhi commented 2 months ago

Hi, I recently used the Graphql client in Spring to subscribe to the AppSync Real-Time service. In the AWS documentation, there is a message type called Keep-alive message as { "type": "ka" }; Therefore, when this type of message is received, because there is no enum for this 'ka' in GraphQlWebSocketMessageType, it gives an error and closes the WebSocket connection.

AWS documentation: https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html#keep-alive-message

My Code:

        String url = prepareRequestUrl();
        WebSocketClient webSocketClient = new TomcatWebSocketClient();
        graphQlClient = WebSocketGraphQlClient.builder(url, webSocketClient)
                .header("Sec-WebSocket-Protocol", "graphql-ws")
                .codecConfigurer(codecConfigurer -> {
                    codecConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
                    codecConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
                })
                .build();

        String subscriptionId = UUID.randomUUID().toString();
        graphQlClient.document(createSubscriptionMessage(topicName, subscriptionId))
                .executeSubscription()
                .map(response -> {
                    log.info("AppSync Message: {}", response);
                    return response.toEntity(String.class);
                })
                .subscribe(callback.consumer(), callback.errorConsumer(), callback.completeConsumer());

The error I received:

org.springframework.core.codec.DecodingException: JSON decoding error: No matching constant for [ka]
org.springframework.graphql.client.WebSocketDisconnectedException: GraphQlSession over TomcatWebSocketSession

With this error, the connection is closed and the subscription on the reactive source is terminated, and nothing can be done. Is there a solution to support non-existent types?

rstoyanchev commented 2 months ago

@mehdizebhi, there are two GraphQL over WebSocket protocols, the old one with subprotocol name "graphql-ws", not maintained since 2018, and its successor with subprotocol name "graphql-transport-ws". You can read about the history of that transition in this blog post.

What AWS is using seems to match the old protocol, but we don't support that. The sub-protocol is actually supposed to be negotiated at WebSocket handshake time, and we do send the name of the sub-protocol, so AWS should be rejecting the handshake, but it's probably not making that checking.

In short, it's not only the KA messages, there are others too that are different. We just don't support the older protocol sequence I'm afraid.