1

I am trying to implement a GraphQL WebSocket-based @subscription on a server (using NestJS @subscription). The server is hosted on an AWS ECS and is behind an ALB. We currently have an AWS API GW connection via VPC-link to our ALB.

I tried to build a dedicated Websocket API GW with the same VPC link we use in the HTTP API GW. I also tried to spin up a new NLB (Network Load Balancer) over our ECS and a new REST VPC link to be used in the dedicated Websocket API GW.

The client and server are communicating over a graphql-transport-ws sub-protocol using graphql-ws library and the communication is working fine on a localhost setup.

When running the following command on our local host I am able to establish a web socket connection:

wscat -c ws://localhost:3000/graphql -s graphql-transport-ws

When running the same against the WebSocket API GW URL

wscat -c wss://*****.execute-api.*****.amazonaws.com/**** -s graphql-transport-ws

I’m getting this: error: Server sent no subprotocol

The error indicates a problem with the sub-protocol so when removing the sub-protocol a connection is established and I am getting a prompt:

Connected (press CTRL+C to quit)
>

However, there’s no indication of reaching the server and it seems like the connection is only made with the WebSocket API GW itself.

When I circumvent the gateway and directly connect an internet-facing NLB I'm able to establish a WebSocket connection.

Bear
  • 13
  • 3

1 Answers1

0

I am not a super Websocket expert, but I understand WebSocket connections will be terminated by the API Gateway and cannot be used as a connection pass-through. You can forward web socket events using AWS_PROXY integration to a graphQL server backend, BUT it's not a maintained direct connection - API Gateway terminates and events towards the backend integration and will not return the integration response to the WebSocket since it is event-driven and not a connection-oriented service - hence the “error: Server sent no subprotocol” you are seeing.

So to use API GW as the WebSocket layer, you would need to build out connection management functionality somewhere to manage the event-based nature of the APIGW and send out data to the APIGW connections or adjust the integration mechanism within the graphql server to utilise the @connection functionality to send responses/notifications to WebSocket consumers.

API GW Websockets are great for building custom solutions but take some effort since you will be configuring the setup for the events.

For a GraphQL API on AWS - I would recommend taking a look at AppSync, which is an AWS Managed GraphQL service - it handles GraphQL subscriptions via WebSockets natively and with zero additional code and its highly scalable out of the box and would simplify the GraphQL hosting burden of an ECS based solution.

I suspect there may be a lot of other reasons for the need to build out using existing GraphQL on ECS, so understand it's not always possible to pivot to something like AppSync. I feel the NLB solution you tried is okay within the existing ECS backend landscape and, as you have noted, is connection-oriented (via NLB), so will achieve the outcome you are after.

  • Thanks, Michael for your detailed answer! as you mentioned, pivoting to AppSync at this point for us is not preferable.. assuming we use an internet facing NLB our concern is security.. i'd appreciate your insights on that matter as well. – Bear Sep 12 '22 at 12:46
  • I feel an ALB would be the preferred option over NLB - this way you can add Cloudfront and WAF into the mix to enhance security using allow controls on WAF/Cloudfront and edge functions to authorize traffic. ALB also operates at Layer 7 so can use sticky sessions to tie websocket connections to a particular container if that is required - may not be a problem yet but at scale will become one. – Michael Walmsley Sep 19 '22 at 23:46