I am setting up an AWS API Gateway Websockets with a custom authorizer on the $connect route, as described here:
My question is -- how do I get the connectionID, ie the identifier I can use to later broadcast to that connected client?
I am setting up an AWS API Gateway Websockets with a custom authorizer on the $connect route, as described here:
My question is -- how do I get the connectionID, ie the identifier I can use to later broadcast to that connected client?
To add content to the integration request, you'll need to use a Request Template.
\$default
. Note the slash. Full documentation here.)$default
. Note the absence of a slash.){
"myConnectionIdProperty": "$context.connectionId",
"myQueryParams": $input.params()
}
Documentation for variables available to you in the template expression can be found here.
(Note that while $request
is a valid variable in the Template Selection Expression, it is not a valid variable in the template itself. Use $input
instead there.)
The issue here was when using HTTP as integration type -- ie having http endpoints being hit when one or more of your API GW routes are invoked ($connect/$disconnect/$invoke). We found that we could not proxy the request (meaning we lose original headers, including auth), but if we need the connection id, we have to specify a Request Template and use something like:
{"connectionId": "$context.connectionId", "body": "$input.body"}
Thanks everyone on trying to document on behalf of AWS. It's a shame that AWS isn't doing it well.
To be able to send data from AWS Websocket API Gateway to your integrated service using VPC Link do the following:
Uncheck Use Proxy Integration
Save
This will allow to get connectionId, query, body in the body of request.
Save
Click on Add Integration Response on the top right
8. Hopefully, it will work. If not, please figure out by testing and then put in the answers here for others. Because AWS would not bother to put up good documentation. Thank you.
I would suggest forget any other type of integration and just use lambda. Because the next problem you will face is getting query parameters that were passed at the time of connection in integration of disconnect.
The question does not specify what type of back end is used. The AWS documentation for AWS API Gateway is geared towards lambda functions - I could not find any help to get the connectionId to my http back end.
Trying the answer by Big Endian, I found some issues - my cakephp back end would not decode the quoted json body. I found the solution, but there were many other steps needed to implement his answer, so here they are:
I created a route key with HTTP Proxy off, and setting up a request template as follows (also very sparse documentation):
Route key: subscribe
This means all requests with {"action": "subscribe"} will route through here
Integration Request type: HTTP
And then for the hard part: setting up the request template. I wanted all "subscribe" requests to use this template and the only way I found of doing this is setting the Template Selection Expression to the same as the Route Selection Expression: $request.body.action, and setting the Template Key to "subscribe".
It ends up being a double test for the same content that the API must do to apply this template - and if anybody has a better way of doing this, please comment.
And then the last step is to enter this as the "Generate template" for 'subscribe':
{"connectionId": "$context.connectionId", "body": $input.body}
Note that in my case, my body was json and the $input.body is not in quotes - the body json gets expanded by the template. I suppose if the body is just a string then the template will be
{"connectionId": "$context.connectionId", "body": "$input.body"}
but then the routing will never get here since the routing needs body to contain the action key in json.
Many thanks to Francois Stark, extremely helpful.
Through my own experimenting, I found you can avoid the need to match specific values of $request.body.action using the $default route and the following format:
{"connectionId": "$context.connectionId", "body": $input.body}
With this configuration, your HTTP endpoint should get the connectionID as body data in all values of 'action' using a single route.
In addition, for getting connectionIDs in the $connect
and $disconnect
routes, the format of the Request Template is the same, but since there is no body data in these events, you can omit the body:
{"connectionId": "$context.connectionId"}
With this configuration, your HTTP endpoint should get the connectionID as body data in the $connect and $disconnect events.
To resolve this, go to your AWS console -> open your AWS CloudShell (Top right in your dashboard)
For the WebSocket server using HTTP_PROXY, you need to modify the @connect route to add the connectionId
1- Enter in the shell:
# List all integrations
aws apigatewayv2 get-integrations --api-id xxxxxxxxx
# Update all @connect integration
aws apigatewayv2 update-integration --integration-id zzzzzzzz --api-id xxxxxxxxx --request-parameters 'integration.request.header.connectionId'='context.connectionId'
2- Don't forget to deploy after or it won't work
Why AWS don't provide you with the connectionId? Because they want you to use Lambda.
You can get connectionId from context variables. See this for the available variables for WebSocket APIs: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-mapping-template-reference.html
In a Lambda function, you can access context variables via event.requestContext.