The x-speakeasy-entity Annotation

Apply x-speakeasy-entity to objects in your OpenAPI spec that represent Terraform entities to include them in the Terraform provider.


components:
schemas:
Order:
description: An order helps you make coffee
x-speakeasy-entity: Order
properties:
id:
type: integer
description: Numeric identifier of the order.
name:
type: string
description: Product name of the coffee.
price:
type: number
description: Suggested cost of the coffee.
required:
- name
- price
type: object


resource "yourprovider_order" "example" {
name = "Filter Blend"
price = 11.5
}

The placement of x-speakeasy-entity affects the Terraform provider's structure.

  • Top Level: Properties are nested objects.
  • Lower Level: Properties above the annotation are flattened.

Top Level


Pet:
x-speakeasy-entity: Pet
...


resource "yourprovider_pet" "example" {
data = { name = "Filter Blend" }
}

Lower Level


Pet:
properties:
data:
x-speakeasy-entity: Pet
...


resource "yourprovider_pet" "example" {
name = "Filter Blend"
}

Warning Icon

Warning

Properties above x-speakeasy-entity are flattened, potentially causing conflicts. Apply the annotation carefully to align with your API's intended user interaction.

The x-speakeasy-entity-operation Annotation

Specifies CRUD (Create, Read, Update, Delete) operations associated with each endpoint in your OpenAPI spec for a Terraform entity.

Use Case: Enables precise mapping of API capabilities to Terraform's resource management, ensuring each API endpoint is accurately represented in Terraform operations for consistent behavior with the API.

Format:

The value is structured as Entity#operation,operation,...#order:

  • Entity represents the name of the entity.
  • operation can be one or more of the following: create, get, update, delete, concatenated with commas.
  • order is optional, and can be used to define a second API call that should be invoked for a given CRUD invocation.

Behavior of Operations

  • Entity:create: Makes the entity a Terraform resource.
  • Entity:read: Ensures consistency with Terraform state and updates attributes.
  • Entity:update: Provides update support for the resource. Without it, attributes are ForceNew.
  • Entity:delete: Enables deletion of the resource. Absence implies no action on deletion.
  • Entity:create,update (Idempotent Operations): When combined, these operations indicate that the API is idempotent. It allows the same API call to be used for both creating new objects and updating existing ones, depending on attribute changes.

paths:
/pet:
post:
tags:
- pet
summary: Add a new pet to the store
x-speakeasy-entity-operation: Pet#create
/pet/{petId}:
get:
tags:
- pet
summary: Info for a specific pet
x-speakeasy-entity-operation: Pet#read
update:
tags:
- pet
summary: Update the pet
x-speakeasy-entity-operation: Pet#update
delete:
tags:
- pet
summary: Delete the pet
x-speakeasy-entity-operation: Pet#delete

One API Operation, Multiple Resources: Optionally, one operation can be annotated with multiple entity annotations. This is useful for cases where a single API call is used across multiple resources, or might annotate / add additional information. For instance, in the following


parameters:
- in: query
name: id
required: false
schema:
type: string
operationId: GetMetadataForResourceOrGroup
x-speakeasy-entity-operation:
- Resource#read#2
- Group#read#2

The x-speakeasy-match annotation

Adjusts the API parameter name to align with a Terraform state property. If mismatches occur, a generation error will highlight appropriate root-level properties for accurate mapping.

Use Case: Use x-speakeasy-match when an API parameter doesn't match a root-level object property.


paths:
/pet/{petId}:
delete:
parameters:
- name: petId
x-speakeasy-match: id
x-speakeasy-entity-operation: Pet#delete

The x-speakeasy-param-readonly Extension

The x-speakeasy-param-readonly extension marks a property as read-only, any user attempt to modify it in Terraform will result in a runtime error.

Use Case: Prevents unintended changes to critical properties in Terraform configurations.


components:
schemas:
Pet:
type: object
properties:
name:
type: string
id:
type: integer
x-speakeasy-param-readonly: true

The x-speakeasy-param-optional Extension

Apply x-speakeasy-param-optional to any property to designate it as optional. This extension takes precedence over the required attribute in the JSON Schema specification.

Use case: Provides flexibility in Terraform configurations by allowing optional settings for certain properties.


components:
schemas:
Pet:
type: object
properties:
name:
type: string
id:
type: integer
x-speakeasy-param-optional: true

The x-speakeasy-param-force-new Extension

Properties marked with this extension will cause the associated Terraform resource to be destroyed and re-created whenever the property value changes. This setting ensures that any alteration to the property triggers a complete recreation of the object.

Use Case: Used for properties that, when altered, require the creation of a new resource instance for proper application.


components:
schemas:
Pet:
type: object
properties:
name:
type: string
id:
type: integer
x-speakeasy-param-force-new: true

The x-speakeasy-param-sensitive Extension

Properties marked as Sensitive will be obscured in the Terraform state and concealed when displayed in the console. This ensures the confidentiality of sensitive data within Terraform operations.

Use Case: Ideal for handling confidential like passwords, tokens, or personal data within Terraform by hiding sensitive information from logs and state files.


components:
schemas:
Pet:
type: object
properties:
name:
type: string
secret:
type: string
x-speakeasy-param-sensitive: true

The x-speakeasy-terraform-ignore: true Extension

When set to true, this extension ensures that the specified property, along with any interactions involving it, is completely omitted from Terraform's state management.

Use Case: Useful for excluding irrelevant, unnecessary, or temporary properties from Terraform's state to keep it clean and focused.


components:
schemas:
Pet:
x-speakeasy-entity: Pet
type: object
properties:
optionalMetadata:
x-speakeasy-terraform-ignore: true
type: string
name:
type: string
required:
- name


resource "petstore_pet" "mypet" {
name = "myPet"
# Attempting to set an ignored parameter results in an error
# optionalMetadata = true
}

The x-speakeasy-type-override: "any" Extension

By setting this extension to "any," the associated attribute is converted into a JSON string. This allows for inline specification of the attribute's value.

Use Case: Useful for accommodating attributes with variable or dynamic structures by allowing the provision of a JSON string inline.


components:
schemas:
Pet:
x-speakeasy-entity: Pet
type: object
properties:
deep:
x-speakeasy-type-override: any
type: object
properties:
object:
type: object
additionalProperties: true
properties:
in:
type: object
properties:
here:
type: string
name:
type: string
required:
- name


resource "petstore_pet" "mypet" {
name = "myPet"
deep = jsonencode({
object = {
with = "anything"
defined = true
}
})
}

The x-speakeasy-param-suppress-computed-diff: true Extension

Suppresses unnecessary Terraform plan changes for computed attributes that are not definitively known until after application (marked as (known after apply)). An attribute is marked as changed only if a GET request confirms a difference between the plan and the API response or the initial creation API call is unavailable. Applies to all nested attributes within the tagged attribute.

Use Case: Useful in scenarios where computed attributes frequently cause spurious plan changes, leading to unnecessary updates in Terraform.


components:
schemas:
Pet:
x-speakeasy-entity: Pet
type: object
properties:
name:
type: string
status:
x-speakeasy-param-suppress-computed-diff: true
type: string

Warning Icon

Warning

Applying this modifier when x-speakeasy-entity-operation: my_resource#read is not defined may result in drift between the Terraform plan and remote state, should updates to attributes happen outside of Terraform changes. Please only apply this when necessary.

The x-speakeasy-conflicts-with Extension

Indicates that a property is in conflict with another, ensuring that certain combinations of properties are not set together. Accepts relative paths to the conflicting attribute(s).

Use Case: Ideal for situations where certain attributes are mutually exclusive or where setting one attribute invalidates another.


components:
schemas:
Pet:
x-speakeasy-entity: Pet
type: object
properties:
name:
type: string
name_prefix:
type: string
x-speakeasy-conflicts-with: name
id:
type: string
generated_name_options:
type: object
properties:
prefix:
type: string
x-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

The x-speakeasy-plan-validators Extension

Enables the addition of custom validation logic (opens in a new tab) to Terraform plan operations, ensuring configurations meet predefined criteria before execution. Applying this extension to a schema attribute triggers the automatic generation of a plan validator that is compatible with the Terraform plugin framework, tailored to the attribute's type. This process enhances the provider's ability to enforce complex validation rules.

Validators created through this extension are organized within a structured directory path beginning with internal/validators/, ensuring a clean and manageable codebase.

Use Case: Essential for scenarios requiring advanced validation logic that JSON Schema cannot accommodate. This extension allows for the implementation of intricate, context-specific validation strategies, ensuring your Terraform provider operates with enhanced accuracy and reliability.


components:
schemas:
Pet:
type: object
x-speakeasy-entity: Pet
properties:
name:
type: string
age:
type: integer
x-speakeasy-plan-validators: AgeValidator

In this scenario, when speakeasy next regenerates the terraform provider, it will bootstrap a custom validator file located at internal/validators/int64validators/age_validator.go, and import it the schema configuration in all places where x-speakeasy-plan-validators: AgeValidator is referenced. You can then modify that file to contain your logic.

Implementation Notes

  1. A plan validator is a type conformant to the terraform-plugin-framework's expected interface. As such, 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 stringvalidators. We will always create/use a file as snake_case.go for a given x-speakeasy-plan-validators value.

  2. A plan validator operates on the raw (untyped) terraform value types. However through use of the included reflection utility you can convert the terraform type into the value type that speakeasy manages (type_mytype.go), which can be useful for applying validators to complex (list, map, object, set) types.

  3. You can do anything you want in a plan validator, including making network calls if you would like to. However, it is generally a good idea to make plan validations side-effect-free. Please refer to hashicorp's guidance in plan validator development (opens in a new tab), or reach out in our Slack if you have questions.

  4. It is possible to have an array of plan validators (x-speakeasy-plan-validators: [MinAgeValidator, MaxAgeValidator]) if you choose to do so.

  5. A validator can only be applied to a resource attribute. They cannot be applied at the same level as the "x-speakeasy-entity" annotation, because that becomes the "root" of the terraform resource. However they can access / refer to any data in the entire resource (for an example, see the x-speakeasy-conflicts-with validator). The annotation will be ignored for datasources.

  6. 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.

Other Keywords and Annotations

Success Icon

Tip

This section is not an exhaustive list of available options. If you're not sure if something is supported please reach out to our team at support@speakeasyapi.dev.

The anyOf Keyword

Terraform's support for anyOf is limited due to its less flexible type system compared to JSON Schema. For instance, managing anyOf with multiple subtypes requires a large set of combined types, leading to practical and implementation challenges.

Consider replacing anyOf in your schema with oneOf or allOf. This adjustment aligns with Terraform's capabilities: oneOf for union types and allOf for intersection types.

For more guidance or to discuss schema adaptations, contact our support team at support@speakeasyapi.dev.

The oneOf Keyword

In Terraform OneOf is defined as a SingleNestedAttribute where each potential child is represented by a unique key. To ensure compliance with oneOf semantics, an object plan validator is used to confirm that only one of these keys is active at any given time.

The allOf Keyword

For allOf, Speakeasy merges all sub-schemas into a single combined attribute, creating a unified schema component that encapsulates all specified properties.