Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't my API Gateway WebSocket send responses with custom domain name configured?

I've configured a WebSocket API with API Gateway and am trying to get a custom domain name configured for it. It's a very simple API that sends messages between connected clients, which stores connection IDs in DynamoDB. In essence, it is similar to the example demonstrated here: https://aws.amazon.com/blogs/compute/announcing-websocket-apis-in-amazon-api-gateway/

All works fine when using the AWS-generated URL i.e. wss://.execute-api.us-west-2.amazonaws.com/. However, when I follow these instructions from AWS to set up a custom regional domain name, I am able to connect but am unable to send messages between clients.

I've checked the Cloudwatch logs for my Lambda functions and don't see any errors and have tried launching an entirely new environment using my CloudFormation template to no avail.

To be very clear, the following connection command triggers my Lambda function correctly and connects my client using the AWS-generated URL AND my own in Route 53.

wscat -c wss://<endpoint> <payload>

The following command, which sends a message to connected clients, works using the AWS-generated URL but NOT my own.

{ "message": "sendMessage", "toId": "193818", "data", "a random msg" }
like image 502
Ben Inada Avatar asked Apr 19 '19 03:04

Ben Inada


1 Answers

We struggled with the same problem, however the api was returning an error:

botocore.errorfactory.ForbiddenException: An error occurred (ForbiddenException) when calling the PostToConnection operation: Forbidden

We ended up manually constructing the callback url for sending back responses: {api_id}.execute-api.{region}.amazonaws.com.

You can get the api id from the request context passed to the lambda function.

python/boto3 code we use:

stage = event['requestContext']['stage']
api_id = event['requestContext']['apiId']
region = 'us-east-1'

domain = f'{api_id}.execute-api.{region}.amazonaws.com'
client = boto3.client('apigatewaymanagementapi', endpoint_url=f'https://{domain}/{stage}')

client.post_to_connection(
    Data='...',
    ConnectionId='...'
)
like image 198
Birne94 Avatar answered Jan 02 '23 06:01

Birne94