19

I am trying to setup an extremely simple WebSocket mock within AWS ApiGateway. However, every attempt I've tried gives me an error:

13:36:52 (X33uOGUfIAMFq7w=) Extended Request Id: X33uOGUfIAMFq7w=
13:36:52 (X33uOGUfIAMFq7w=) Verifying Usage Plan for request: X33uOGUfIAMFq7w=. API Key: API Stage: redacted/prod
13:36:52 (X33uOGUfIAMFq7w=) API Key authorized because route '$connect' does not require API Key. Request will not contribute to throttle or quota limits
13:36:52 (X33uOGUfIAMFq7w=) Usage Plan check succeeded for API Key and API Stage redacted/prod
13:36:52 (X33uOGUfIAMFq7w=) Starting execution for request: X33uOGUfIAMFq7w=
13:36:52 (X33uOGUfIAMFq7w=) WebSocket Request Route: [$connect]
13:36:52 (X33uOGUfIAMFq7w=) Client [UserAgent: null, SourceIp: redacted] attempts to connect to WebSocket API [redacted].
13:36:52 (X33uOGUfIAMFq7w=) Execution failed due to configuration error: statusCode should be an integer which defined in request template
13:36:52 (X33uOGUfIAMFq7w=) Client [UserAgent: null, SourceIp: redacted] failed to connect to API [redacted].

As far as I can tell, I've followed the most basic configuration possible. I do not need any responses or templates, just simple a WebSocket connection that allows me to connect to it and do nothing, or perhaps respond to ping requests with a pong eventaully.

api route $connect

All authorizations and API keys are disabled. No request templates or integration responses are setup since I do not need them. Again, the goal is to just be able to have a dumb WebSocket that can be connected to.

no request templates

However, whenever I try to connect to it, I get a 500 error with the error logs from above about a status code.

WebSocket connection to 'wss://redacted.execute-api.us-east-1.amazonaws.com/prod' failed: Error during WebSocket handshake: Unexpected response code: 500
lightswitch05
  • 9,058
  • 7
  • 52
  • 75

2 Answers2

50

Using the following sources (below), I was able to get a quick and loose example AWS API Gateway connection working use MOCK endpoints with web sockets. I'm sure this can be flushed out more to provide an even better understanding of different request/response body messages and codes..

  1. First, go to API Gateway, click Create API

  2. For Choose the protocol, select WebSocket

  3. Give the API a name, and use the example $request.body.message for the route selection expression

  4. Click the Create API button

  5. Select the new API from the side pane, and click Routes

  6. Select the $connect route

  7. Under Route overview, select the Mock radio button for endpoint

  8. For the Request Template, enter an expression (using 200 for example).

  9. For Template Key, enter a key (using 200 for example)

  10. For the popup window on passthrough behavior, select No, Use Current Settings for now

  11. Click on the Template Key 200, and enter a template: {"statusCode" : 200} and then click the Save button. connect integration request

  12. Select Route Overview to go back to the $connect overview page and then select the Add Integration Response button

  13. Create a response key of $default, which will reference the $default key under Routes connect integration response

  14. For the $disconnect route, please repeat steps 7 - 13 for this specific route. disconnect route

  15. Once done setting up the $disconnect route, please select the $default route under the Routes pane. default route

  16. Create an Integration Request the same way that was done for $connect and $disconnect (steps 7 - 11)

  17. For Integration Response under $default, we will be setting the route response up slightly different than $connect and $disconnect as those 2 routes' responses actually reference the $default response within their own respective Integration Responses.

  18. Create a response key of $default

  19. Enter a Template Selection Expression (using 200 for this example)

  20. Then create a Template Key (using 200 for this example)

  21. Click on the Template Key 200, and enter a template: {"statusCode" : 200, "connectionId" : "$context.connectionId"} and then click the Save button. default response

  22. {"connectionId" : "$context.connectionId"} was added to the response payload to show how variables can be used within the response to represent an actual value of the connection.

  23. Finally, under the Actions dropdown, select Deploy API, and enter a deployment stage name. This should generate a WebSocket URL that can now be connected to e.g. (wss://#######.execute-api.us-east-1.amazonaws.com/Test)

  24. Using wscat via cli, I am now able to connect to my WebSocket URL (see source below for installing wscat): wscat -c wss://#######.execute-api.us-east-1.amazonaws.com/Test cli websocket

Sources:

Woodrow
  • 2,740
  • 1
  • 14
  • 18
  • 5
    Very detailed, thank you. I believe point 13. is a bit misleading, since it does not reference the $default route, but it's the $default key. https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-route-response-selection-expressions – Kostadin Mandulov Jul 22 '19 at 15:59
  • 1
    Thank you for the step by step guide! Helped a lot for getting a good starting point. – duwo Feb 11 '20 at 13:33
  • I had to remove the quotes from the statusCode property in the integration requests to get a proper match :( – Geerten Oct 20 '20 at 14:53
  • 5
    The key takeaway for me is that the `$connect` route cannot return a response. – Etienne Martin Feb 13 '22 at 01:06
  • 2
    24 steps for the simplest possible WebSocket example! – Rupert Rawnsley Mar 04 '22 at 16:17
  • @RupertRawnsley - can't tell if that is a good or bad thing? Lol, granted this is a few years old now. – Woodrow Mar 05 '22 at 19:28
  • 1
    @Woodrow I'm damning the perversity of AWS while simultaneously praising your determination and guile in working around it. – Rupert Rawnsley Mar 05 '22 at 23:09
  • 2
    @EtienneMartin do you mean it is not possible to return something to a client on connect? I fail in retrieving the connection id from a browser but I get it in wscat. On the client I simply try to get the connectionId from `onOpen` but I don't receive it. – Sandro_V Mar 08 '22 at 10:34
  • 3
    Correct, this is not possible to return anything from the $connect event. If you look closely at the last screenshot, you can see that @Woodrow pressed enter, which triggered the $default route with the correct response. Learned that the hard way. – Etienne Martin Mar 08 '22 at 14:34
7

I've automated the steps described by Woodrow using CloudFormation so now anyone can reproduce it more easily. The template can be found here: https://gist.github.com/maatthc/9d2dfe0448733f0ee1624d658fbac80f . To create a new stack using it you should:

  1. Download the template to your machine.
  2. Head to Cloudformation in the AWS Console (https://ap-southeast-2.console.aws.amazon.com/cloudformation/) - Change your AWS Region.
  3. Click in "Create Stack"
  4. Choose "Upload a template file" and use the template you've downloaded.
  5. Click Next, give the stack a name and click Next again.
  6. Click Next and "Create Stack".

I hope it helps.

Cheers

  • It fails to generate and rollsback. Probably something related to roles. I tried to specify a role for ApiGateway to log in CloudWatch but it also fails saying that the role is incorrect or can´t be applied. I´m pretty new to AWS, does it make sense this error? – diegosasw Feb 19 '21 at 15:00
  • Fixed it, it seems my role didn´t have the proper trust relationship as per https://aws.amazon.com/premiumsupport/knowledge-center/cloudformation-role-arn-error/ and after that it didn´t have permissions to POST something or to create new roles, so I gave admin policies. If you know which minimum policies would the Role require, please let me know so that I can grant just the minimum it requires :) Thanks for your answer! – diegosasw Feb 19 '21 at 15:15