Validation and Dependencies
Prevent Conflicting Attributes
The x-speakeasy-conflicts-with
extension indicates that a property conflicts with another, ensuring that certain combinations of properties are not set together. This is ideal for situations where certain attributes are mutually exclusive or setting one attribute invalidates another.
components:schemas:Pet:x-speakeasy-entity: Pettype: objectproperties:name:type: stringname_prefix:type: stringx-speakeasy-conflicts-with: nameid:type: stringgenerated_name_options:type: objectproperties:prefix:type: stringx-speakeasy-conflicts-with:- ../name_prefix- ../name- ../id
resource "example_pet" "happy_pet" {name = "Mrs Poppy"name_prefix = "Mrs"}
$ terraform plan│ Error: Invalid Attribute Combination││ with example_pet.happy_pet,│ on provider.tf line 39, in resource "example_pet" "happy_pet":│ 3: name_prefix = "test"││ Attribute "name" cannot be specified when "name_prefix" is specified
Enforce Mutually Exclusive Attributes (x-speakeasy-xor-with)
The x-speakeasy-xor-with
extension ensures that exactly one of the listed attributes must be configured at the same time. If multiple attributes are set simultaneously or if no attribute is set, Terraform plan validation fails. This differs from x-speakeasy-conflicts-with
in that it requires exactly one attribute to be set, while conflicts-with
allows zero or one attribute to be set.
components:schemas:Pet:x-speakeasy-entity: Pettype: objectproperties:this:type: stringthat:type: stringanother:type: string# user MUST configure exactly one of: this, that, or anotherx-speakeasy-xor-with:- ../this- ../that
resource "example_pet" "happy_pet" {this = "value1"that = "value2" # Error: exactly one field must be set}
$ terraform plan│ Error: Invalid Attribute Combination││ with example_pet.happy_pet,│ on provider.tf line 2:│ 2: that = "value2"││ Exactly one of attributes [this, that, another] must be specified
Enforce Required Attribute Dependencies (x-speakeasy-required-with)
The x-speakeasy-required-with
extension ensures that when the annotated field is configured, all the specified dependent fields must also be configured. This is useful for enforcing that certain fields are always configured together.
components:schemas:Pet:x-speakeasy-entity: Pettype: objectproperties:name:type: stringage:type: integerbreed:type: string# when breed is set, name and age must also be setx-speakeasy-required-with:- ../name- ../age
resource "example_pet" "happy_pet" {breed = "Labrador" # Error: name and age must also be set when breed is set}
$ terraform plan│ Error: Missing Required Attributes││ with example_pet.happy_pet,│ on provider.tf line 2:│ 2: breed = "Labrador"││ The following attributes must be configured when 'breed' is specified: [name, age]
OpenAPI Plan Validators
Speakeasy automatically generates certain Terraform configuration value validation handlers based on your OpenAPI specification. When configuration validation is defined, Terraform raises invalid value errors before users can apply their configuration for a better user experience.
By default, these OpenAPI specification properties are automatically handled:
- For
string
types:enum
,maxLength
,minLength
, andpattern
- For
integer
types:enum
,minimum
, andmaximum
- For
array
types:maxItems
,minItems
, anduniqueItems
For use cases not automatically handled, add custom validation logic or reach out to the team.
Add Custom Validation Logic
Use the x-speakeasy-plan-validators
extension to add custom validation logic to Terraform plan operations and ensure configurations meet predefined criteria before execution. This extension is essential for scenarios requiring advanced validation logic that JSON Schema cannot accommodate.
components:schemas:Pet:type: objectx-speakeasy-entity: Petproperties:name:type: stringage:type: integerx-speakeasy-plan-validators: AgeValidator
In this scenario, when Speakeasy next generates the Terraform provider, it will bootstrap a custom validator file located at internal/validators/int64validators/age_validator.go
, and import the schema configuration wherever x-speakeasy-plan-validators: AgeValidator
is referenced. You can modify the validator file to contain your logic.
Implementation Notes
-
A plan validator is a type conformant to the
terraform-plugin-framework
expected interface. A unique plan validator will be bootstrapped in the appropriate subfolder for the Terraform type it is applied to:boolvalidators
,float64validators
,int64validators
,listvalidators
,mapvalidators
,numbervalidators
,objectvalidators
,setvalidators
, orstringvalidators
. Speakeasy will always create and use a file assnake_case.go
for a givenx-speakeasy-plan-validators
value. -
A plan validator operates on the raw (untyped) Terraform value types. However, you can convert a Terraform type to a value type Speakeasy manages (
type_mytype.go
) by using the included reflection utility. This is useful for applying validators to complex types likelist
,map
,object
, andset
. -
While working with a plan validator, you have the ability to perform various tasks, including initiating network requests. However, it’s important to ensure that plan validations do not result in any unintended side effects. Please refer to the HashiCorp guidance on plan validator development (opens in a new tab) or reach out in our Slack if you have questions.
-
It is possible to have an array of plan validators, for example,
x-speakeasy-plan-validators: [MinAgeValidator, MaxAgeValidator]
. -
A validator can only be applied to a resource attribute. Validators cannot be applied at the same level as the
x-speakeasy-entity
annotation because that becomes the “root” of the Terraform resource. However, validators can access or refer to any data in the entire resource (for an example, see thex-speakeasy-conflicts-with
validator). The annotation will be ignored for data sources. -
Speakeasy regenerations do not delete user-written code. If the validator is no longer in use, it will be ignored (no longer referenced) but the source file will remain. You might want to delete such an orphaned validation file for repository hygiene.