Problem Statement
Currently, when defining a resource in Terraform, two separate structs are often required:
- HCL Schema Struct : Used to define the resource schema in HCL.
- API Struct : Used to interact with the backend API.
In many cases, the HCL structure maps directly to the backend structure (often a 1:1 relationship). However, the HCL types (types.String, types.Number, etc.) cannot be directly used for JSON marshalling and unmarshalling because they lack support for the MarshalJSON and UnmarshalJSON interfaces. This limitation forces developers to duplicate structs and perform additional mapping between the HCL and API representations.
Proposed Solution
Add MarshalJSON and UnmarshalJSON methods for the basic HCL types (types.String, types.Number, types.Bool, etc.). This enhancement would allow HCL structs to be directly used for JSON serialization and deserialization, significantly reducing the need for duplicate struct definitions.
For example, the implementation for types.String could look like this:
func (s StringValue) MarshalJSON() ([]byte, error) {
return json.Marshal(s.value)
}
func (s *StringValue) UnmarshalJSON(data []byte) error {
var v string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
s.state = attr.ValueStateKnown
s.value = v
return nil
}
Example Usage
With this feature, a single struct could be used for both HCL schema definition and API interactions:
type MyResource struct {
Name types.String `tfsdk:"name" json:"base"`
AnotherAttribute types.Bool `tfsdk:"another_attribute" json:"anotherAttribute"`
}
This approach ensures that:
- HCL fields are properly tagged for schema definition (tfsdk).
- JSON fields are correctly serialized/deserialized for API communication (json).
Benefits
- Reduced Boilerplate : Eliminates the need for duplicate structs and manual mapping between HCL and API representations.
- Improved Developer Experience : Simplifies resource implementation by allowing a single struct to handle both HCL and API requirements.
- Backward Compatibility : This change would not interfere with existing usages of HCL types, as it only adds optional JSON marshalling/unmarshalling support.
Open Questions
- Are there already plans to address this issue?
- Would this addition align with the design philosophy of Terraform’s SDK?
This change seems relatively small in scope but has the potential to significantly improve the developer experience when implementing new resources.
Is this something that could be considered for implementation?