How to handle JSON input into Data Resource with multiple types with the Terraform SDK?

Hi @grantcurell!

The SDK is built around the types in Terraform’s type system, rather than Go’s type system. Terraform does have an “any” type constraint, but unfortunately the current SDK doesn’t support declaring arguments in that way because it was designed around the capabilities of Terraform v0.11 and earlier, and this “any” constraint is a newer feature that isn’t compatible with the SDK’s assumptions.

The typical approach today is, I think, what you already tried: define a string attribute, often with a name ending in _json to be explicit about it, and then decode that value as JSON inside the provider code.

A team at HashiCorp is currently working on a new SDK design that should support these newer capabilities, including the possibility of marking an argument as having a dynamically-chosen type. There’s already a low-level component of it available in experimental form, but it’s at a much lower level of abstraction than the current SDK and so I wouldn’t suggest writing typical providers with it. Another layer on top of that with a similar level of abstraction as the current SDK will follow later, but is still in the design stages.

If you name your current argument with a _json suffix then you can in principle later introduce a new attribute without that suffix once there is SDK support for the any type constraint, in order to move forward to the nicer design without a breaking change.

(The internal complexity here, in case you are interested, is that implementing runtime type selection as you’re accustomed to with interface{}, and as Terraform does with any, requires sending the dynamic type information over to the provider plugin along with the value. Since Terraform didn’t historically have this capability, the existing SDK is built around the idea that everything is statically-typed, and so although the modern wire protocol for Terraform providers can serialize type information in principle, the SDK’s internals are not designed to retain that additional metadata as they pass data through to provider-facing APIs like schema.ResourceData.)

1 Like