Closed xavicolomer closed 2 years ago
¡Hola @xavicolomer !
I have not implemented full support for WebSocket in this module, because I have not used them in my projects (yet) but maybe you can see what is missing and add the required code for that?
Ok, I will give it a look!
I didn't know if it was fully developed. Thanks!
don't use the $default stage name hardcoded in the module, but I managed to get this working with websockets in my own fork with this tweak
@sjf3 are you able to share an example? I have used create_default_stage = false
to prevent $default
being created (but I then end up with no stages). My lambda is being created and the routes are all set to AWS_PROXY
but they're not getting wired up.
I'm still tweaking my files but any pointers would be really helpful.
# Default stage
resource "aws_apigatewayv2_stage" "default" {
count = var.create && var.create_default_stage ? 1 : 0
api_id = aws_apigatewayv2_api.this[0].id
name = var.protocol_type == "HTTP" ? "$default" : "default" // changed to work with websockets
auto_deploy = true
...
I changed that one line and it all just works. You do need a stage. The name just can't be $default
@lllama looks like I also made this edit as well
resource "aws_apigatewayv2_route_response" "this" {
for_each = var.create && var.create_routes_and_integrations && var.protocol_type == "WEBSOCKET" ? var.integrations : {}
api_id = aws_apigatewayv2_api.this[0].id
route_id = aws_apigatewayv2_route.this[each.key].id
route_response_key = "$default" // must be exactly this hardcoded value
}
Thanks @sjf3. I've made your two changes but my routes still aren't getting wired up. Here's the terraform I'm using:
provider "aws" {
region = "eu-west-2"
# Make it faster by skipping something
skip_get_ec2_platforms = true
skip_metadata_api_check = true
skip_region_validation = true
skip_credentials_validation = true
# skip_requesting_account_id should be disabled to generate valid ARN in apigatewayv2_api_execution_arn
skip_requesting_account_id = false
}
locals {
domain_name = "terraform-aws-modules.modules.tf" # trimsuffix(data.aws_route53_zone.this.name, ".")
subdomain = "complete-http"
}
###################
# HTTP API Gateway
###################
module "api_gateway" {
source = "../terraform-aws-apigateway-v2"
name = "test-ws-test"
description = "My awesome test Websocket API Gateway"
protocol_type = "WEBSOCKET"
route_selection_expression = "$request.body.action"
create_api_domain_name = false
default_stage_access_log_destination_arn = aws_cloudwatch_log_group.logs.arn
default_stage_access_log_format = "$context.identity.sourceIp - - [$context.requestTime] \"$context.httpMethod $context.routeKey $context.protocol\" $context.status $context.responseLength $context.requestId $context.integrationErrorMessage"
integrations = {
"$connect" = {
lambda_arn = module.lambda_function.this_lambda_function_arn
},
"$disconnect" = {
lambda_arn = module.lambda_function.this_lambda_function_arn
},
"$default" = {
lambda_arn = module.lambda_function.this_lambda_function_arn
}
}
tags = {
Name = "dev-api-new"
}
}
resource "random_pet" "this" {
length = 2
}
resource "aws_cloudwatch_log_group" "logs" {
name = "test-ws-test"
}
module "lambda_function" {
source = "terraform-aws-modules/lambda/aws"
function_name = "${random_pet.this.id}-lambda"
description = "My awesome lambda function"
handler = "handler.handler"
runtime = "python3.8"
publish = true
source_path = "../aws"
allowed_triggers = {
AllowExecutionFromAPIGateway = {
service = "apigateway"
source_arn = "${module.api_gateway.this_apigatewayv2_api_execution_arn}/*/*/*"
}
}
}
I've used this terraform that I found https://github.com/ustaxcourt/ef-cms/blob/staging/web-api/terraform/api/websockets.tf and have been able to create an API that's wired up, so I'm going to try and work out what the differences are.
Hopefully everyone spotted my deliberate mistake - I needed to use the invoke arn for the lambda functions:
integrations = {
"$connect" = {
lambda_arn = module.lambda_function.this_lambda_function_invoke_arn
},
"$disconnect" = {
lambda_arn = module.lambda_function.this_lambda_function_invoke_arn
},
"$default" = {
lambda_arn = module.lambda_function.this_lambda_function_invoke_arn
}
}
I also had one too many *
in my allowed_triggers
in the lambda module. This sorted out the 500 errors I was getting.
I was getting 429
errors when connecting but these look like they are fixed once I enable throttling on the API stage. When I apply my terraform, the console shows that throttling is disabled. If I enabled it, save my config, then try to disable it again and save, then the console complains that this is an invalid throttling setting, which makes me think that throttling is required (for websockets only?) However, I've just done a destroy/apply cycle and the new API seems happy without a throttling setting, so now I'm just confused.
In one final twist, I have also just backed out the $default
-> default
stage name change, and the new API runs as expected. @sjf3 can I check how you were testing your websocket API? I was using https://github.com/vi/websocat which works well enough but when I pasted the execution URI containing $default
into my bash prompt, then bash was expanding it to an empty string, which caused 403 errors. Wrapping the URI in single quotes fixed that.
I followed this guide when initially getting setup. https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-wscat.html
So looking at that example, they have the following command for invoking the API:
wscat -c wss://aabbccddee.execute-api.us-east-1.amazonaws.com/test/
and test
is the stage name. If you replace that with $default
, then there's a strong chance your shell will replace that with nothing.
So
wscat -c wss://aabbccddee.execute-api.us-east-1.amazonaws.com/$default/
becomes
wscat -c wss://aabbccddee.execute-api.us-east-1.amazonaws.com//
Which will give 403
or some other error. If you were to wrap the URL in single quotes:
wscat -c 'wss://aabbccddee.execute-api.us-east-1.amazonaws.com/$default/'
then the shell shouldn't make any changes and wscat
should be able to connect.
$default is the default route key if another route key doesn't match. This isn't REST you don't have path based routing. In this example wscat -c wss://aabbccddee.execute-api.us-east-1.amazonaws.com/test/
test
is the stage $default will handle anything after $connect if another route doesn't match. You can use jsonpath expressions to match routes based on the messages sent. Like if you were doing jsonRPC 2.0 over websockets you could match on the method string and route to different lambda handlers or for only handling a few routes you can just put a switch statement in the $default route handler.
Agreed but the changing of the stage name:
# Default stage
resource "aws_apigatewayv2_stage" "default" {
count = var.create && var.create_default_stage ? 1 : 0
api_id = aws_apigatewayv2_api.this[0].id
name = var.protocol_type == "HTTP" ? "$default" : "default" // changed to work with websockets
auto_deploy = true
...
will affect the test
portion of the URI, rather than any routing. API gateway will do "path-based" routing for any stages that are defined. Only once wscat
and friends have connected to this URI will the route key come into play. Having $default
as the stage appears to just be a coincidence with it having the same name as the $default
route in websockets.
So I can confirm that this works out of the box with websockets. @antonbabenko, would you be interested in an example that implements the AWS Chat code sample? (https://docs.aws.amazon.com/code-samples/latest/catalog/code-catalog-python-example_code-apigateway-websocket.html) If so, I'll put a pull request together.
@lllama Yes, it would be great if you can add a new folder examples/complete-websocket
similar to examples/complete-http with real WebSocket configuration and Python code.
I don't have immediate plans to use WebSockets features in the near future myself, so any help is highly appreciated.
@lllama Hi there, still interested in contributing this example?
Just ACKing this request. I'll try and put together a PR when I get a minute. (semi-related XKCD: https://xkcd.com/979/ )
@svenlito See #46
This issue has been automatically marked as stale because it has been open 30 days with no activity. Remove stale label or comment or this issue will be closed in 10 days
This issue has been automatically marked as stale because it has been open 30 days with no activity. Remove stale label or comment or this issue will be closed in 10 days
This issue was automatically closed because of stale in 10 days
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
This issue has been resolved in version 5.0.0 :tada:
Hi there!
Is there any websockets template I can base on?
I tried with one of the examples but the domain and domain_certificate_arn are required. All I would need is a simple websockets endpoint integrated with a lambda.
Thanks!