Generate JSON array from map

Hello all,
Is there a way to generate some Terraform JSON (version 0.12 btw), using a template file?

Here is what the template file look like:

{
    "environment": ${TO_BE_REPLACED}
}

Here is my map:

variable "endpoints" {
  type = list
  default = [
    { POF = "pif" },
    { PAF = "pouf" }
  ]
}

And here is what I’d like to obtain:

{
    "environment": [
      {
        "name": "POF",
        "value": "pif"
      },
      {
        "name": "PAF",
        "value": "pouf"
      }
    ]
  }

So far, I “manually” got something that looked like I wanted:

data "template_file" "task_template" {
  template = file("${path.module}/data/${var.service_name}.json")
  vars = {
    TO_BE_REPLACED = jsonencode(list({"name" = "POF", "value" = "pif"}))
  }
}

But, I’m struggling getting my array around this…

Any ideas? Thank you!

Thanks to the help by my colleague Sergey, I got around this; the only missing part was the for loop, and using a map rather than a list

variable "endpoints_map" {
  type = map(string)
  default = {
    "POF"="pif",
    "PAF"="pouf"
  }
}
locals {
  remap_entries = [
  for k, v in var.endpoints_map : {
      name = k
      value = v
    }
  ]
}
data "template_file" "task_template" {
  template = file("${path.module}/data/${var.service_name}.json")
  vars = {
    TO_BE_REPLACED = jsonencode(local.remap_entries)
  }
}

Hi @anthonydahanne!

The template_file data source is primarily there for Terraform 0.11 users. For Terraform 0.12 you can use the templatefile function instead, which is built in to Terraform and integrates better with the rest of the language.

With that said, for generating JSON we should always use jsonencode rather than templates, because then Terraform can ensure that the result has valid JSON syntax. It’s a very common problem to try to generate by concatenating strings together and find that the result isn’t valid due to incorrect escaping, missing colons, etc.

For a simple example, you can just include the jsonencode call directly in the configuration:

# In your main configuration

locals {
  task_template = jsonencode({
    "environment": jsonencode([{"name" = "POF", "value" = "pif"}])
  })
}

If the JSON value you want to generate is too large to include directly in the Terraform configuration, or as in your case the specific file to choose depends on a variable, you can use jsonencode from your external template:

# In your main configuration

locals {
  task_template = templatefile("${path.module}/data/${var.service_name}.json.tmpl", {
    environment = [{"name" = "POF", "value" = "pif"}]
  })
}

…and then, in the .json.tmpl file:

${jsonencode({
  "environment": environment
})}

Because the entire template is a single interpolation sequence, the result will just be the result of that jsonencode call and nothing else.

1 Like