title: Extracting data structures from terraform ResourceData in a provider
body: <p>tldr: Is there a way to turn Schema.ResourceData into a typed data structure or JSON corresponding to my schema.Resource?</p>
  <p>I'm starting to create a new provider. My schema.Resource has two nested maps and each of the fields is typed. When Create is called I need to turn schema.ResourceData into JSON for the backend API.</p>
  <p>Extracting the data from ResourceData seems both more difficult and more fragile than I'd expect given that all the types are known beforehand and there's checking going on (a bad field throws an error before the Create is called). However, looking at some examples, hashi-cups, terraform-provider-aws, and others I see <em>lots</em> of casting to maps and lists of interfaces.</p>
  <p>For example, here's a snippet from <a href="https://github.com/hashicorp/terraform-provider-aws/blob/main/internal/service/batch/compute_environment.go" rel="nofollow noreferrer">compute_environment in terraform-provider-aws</a></p>
  <pre><code>    if v, ok := d.GetOk(&quot;compute_resources&quot;); ok &amp;&amp; len(v.([]interface{})) &gt; 0 &amp;&amp; v.([]interface{})[0] != nil {
          input.ComputeResources = expandComputeResource(v.([]interface{})[0].(map[string]interface{}))
  </code></pre>
  <p>Is this really the best practice for extracting values from ResourceData? I feel that I must be missing something, but at the same time can't seem to find a better way.</p>
  <p>Are there tools/methods/??? to automate the extraction into typed structures that match the Schema or am I condemned to a life of doing things like below? I started out hand-crafting my schema.Resource, is this a mistake and I should be using some higher-level abstraction that generates the schema.Resource and the extraction code from a common source?</p>
  <pre><code>    communities := data.([]interface{})
      for _, community := range communities {
          comm := community.(map[string]interface{})
          if err := addCommunity(root, comm); err != nil {
              return err
          }
      }
  </code></pre>