Perform validation of variable object key

I have the following variable declaration using optional defaults feature (terraform 1.0.x release:

However I cannot get the variable validation to work. Right now I can send a map value of

  http_verb_default_ito_milliseconds = {
    POSTS = 10000
  }

and it will not fail. What am I doing wrong in the validation?

variable "http_verb_default_ito_milliseconds" {
  type = object({
    GET    = optional(number)
    POST   = optional(number)
    PUT    = optional(number)
    PATCH  = optional(number)
    DELETE = optional(number)
  })
  default     = {}
  description = "The integration timeout for all HTTP verbs for an endpoint (milli seconds)"
  validation {
    condition = alltrue([
      for verb in keys(var.http_verb_default_ito_milliseconds) : contains(["GET", "POST", "PUT", "PATCH", "DELETE"], verb)
    ])
    error_message = "The supported HTTP verbs are GET, POST, PUT, PATCH and DELETE."
  }
}

locals {
  system_default_ito = 29000
  http_verb_default_ito = defaults(var.http_verb_default_ito_milliseconds, {
    GET    = local.system_default_ito
    POST   = local.system_default_ito
    PUT    = local.system_default_ito
    PATCH  = local.system_default_ito
    DELETE = local.system_default_ito
  })
}

Hi @jeffery,

What you saw here is working as designed: an object type constraint requires at least the specified attributes… Any others will be automatically discarded as part of type conversion.

The object within the module will still have only the attributes you specified. It’s not typical to reject additional attributes as long as the module has everything needed to do its work, because that helps avoid problems when objects are being passed between modules and resources as a whole and the consuming module hasn’t yet been updated to expect a new attribute that the source module has been updated to produce.

In your case, you might find it better to use map(number) as your type constraint, specifying that the keys will be chosen by the caller rather than your type constraint, but then use validation to constrain which map keys you will allow.

Hi @apparentlymart , thanks for the suggestion.

If I use a map(number) , is there a way of setting default values for each of those map keys?

Hi @jeffery,

I think the simplest way would be to merge the caller’s given map with a map of defaults, like this:

locals {
  http_verb_default_ito_milliseconds = merge(
    {
      GET    = local.system_default_ito
      POST   = local.system_default_ito
      PUT    = local.system_default_ito
      PATCH  = local.system_default_ito
      DELETE = local.system_default_ito
    },
    var.http_verb_default_ito_milliseconds,
  )
}

Because merge will resolve key conflicts by discarding the elements from earlier arguments, this will allow var.http_verb_default_ito_milliseconds to override zero or more of the provided defaults.

Thanks @apparentlymart . This works for me. Appreciate the help :slight_smile: