17

In an attempt to create a route key named $disconnect for an API Gateway, I'm running the snippet below, while var.route_name should receive the string "disconnect":

resource "aws_apigatewayv2_route" "route" {
  api_id    = var.apigw_api.id
  route_key = "$${var.route_name}"
  # more stuff...
}

But it's not escaping it correctly. I coulnd't find a proper way to emit a $, followed by var.route_name's content.

How to do that?

Tar
  • 8,529
  • 9
  • 56
  • 127

3 Answers3

23

In Terraform's template language, the sequence $${ is the escape sequence for literal ${, and so unfortunately in your example Terraform will understand $${var.route_name} as literally ${var.route_name}, and not as a string interpolation at all.

To avoid this, you can use any strategy that causes the initial $ to be separate from the following ${, so that Terraform will understand the first $ as a literal and the remainder as an interpolation sequence.

One way to do that would be to present that initial literal $ via an interpolation sequence itself:

"${"$"}${var.route_name}"

The above uses an interpolation sequence that would typically be redundant -- its value is a literal string itself -- but in this case it's grammatically useful to change Terraform's interpretation of that initial dollar sign.

Some other permutations:

join("", ["$", var.route_name])
format("$%s", var.route_name)
locals {
  dollar = "$"
}

resource "aws_apigatewayv2_route" "route" {
  route_key = "${local.dollar}${var.route_name}"
  # ...
}

Again, all of these are just serving to present the literal $ in various ways that avoid it being followed by either { or ${ and thus avoid Terraform's parser treating it as a template sequence or template escape.

Martin Atkins
  • 62,420
  • 8
  • 120
  • 138
2

There probably exists an easier way to escape a $ in hcl2 string interpolation, but the format function will also assist you here:

resource "aws_apigatewayv2_route" "route" {
  api_id    = var.apigw_api.id
  route_key = format("$%s", var.route_name)
  # more stuff...
}
Matthew Schuchard
  • 25,172
  • 3
  • 47
  • 67
0

If you are trying to dynamically set a variable name (ie the variable name depends on another variable), this is not possible. Otherwise you could do this:

resource "aws_apigatewayv2_route" "route" {
  api_id    = var.apigw_api.id
  route_key = "$$${var.route_name}"
  # more stuff...
}

Instead, create a map route_keys and choose the key based on the name:

locals {
  route_keys = {
    route_name1 = ...
    route_name2 = ...
  }
}

resource "aws_apigatewayv2_route" "route" {
  api_id    = var.apigw_api.id
  route_key = local.route_keys[var.route_name]
  # more stuff...
}
Oliver
  • 27,510
  • 9
  • 72
  • 103