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

As far as I can tell, the Terraform SDK does not support the Interface type. I have this big JSON dictionary with a bunch of data with varying types I want to pass from a data resource into a resource. Right now I have a really ugly hack where I make everything a string and then fix the type in the resource.

Is there a better way to accomplish this? I figured the Interface type must not be there for a reason - is there a canonical solution to this problem?

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

@apparentlymart

As always your responses are the best! I recognize you from Reddit! I really appreciate your taking the time to explain the inner workings - I really like that stuff.

That all makes complete sense. The various pieces are coming together - down the road I might take a look at the experimental plugin. I like playing with that sort of thing.

Thanks again!