Home > Blockchain >  Terraform Custom Provider - Data Source Schema
Terraform Custom Provider - Data Source Schema

Time:05-02

I am working on creating a custom terraform provider by using terraform sdk. I am trying to read data from the existing API GET call. I am finding it difficult to map the JSON response from an API to terraform schema. This is my data source schema:

func dataSourceProjects() *schema.Resource {
return &schema.Resource{
    ReadContext: dataSourceProjectsRead,
    Schema: map[string]*schema.Schema{
        "members": &schema.Schema{
            Type:     schema.TypeList,
            Elem:     &schema.Schema{Type: schema.TypeString},
            Computed: true,
        },
        "owners": &schema.Schema{
            Type:     schema.TypeList,
            Elem:     &schema.Schema{Type: schema.TypeString},
            Computed: true,
        },
    },
}
}

This is the API JSON response:

{
"members": [
    "test12",
    "test8800",
    "test0032",
    "test1234",
],
"owners": [
    "test000",
    "test111",
    "test12",
    "test1234",
]
}

This is my Data source read function

func dataSourceProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

client := &http.Client{Timeout: 10 * time.Second}

// Warning or errors can be collected in a slice type
var diags diag.Diagnostics

req, err := http.NewRequest("GET", fmt.Sprintf("%s/test/team", "https://myurl/v1"), nil)
req.Header.Add("Authorization", "Bearer xxxxx")
if err != nil {
    return diag.FromErr(err)
}

r, err := client.Do(req)
if err != nil {
    return diag.FromErr(err)
}
defer r.Body.Close()
members := make([]string, 0)
err = json.NewDecoder(r.Body).Decode(&members)
if err != nil {
    return diag.FromErr(err)
}

if err := d.Set("members", members); err != nil {
    return diag.FromErr(err)
}

// always run
d.SetId(strconv.FormatInt(time.Now().Unix(), 10))

return diags

}

I keep getting this error: Error: json: cannot unmarshal object into Go value of type []string

CodePudding user response:

I believe you need to unmarshal to a type matching the format of your JSON instead of attempting to somehow implicitly transform it into a string slice:

members := make(map[string][]string)
err = json.NewDecoder(r.Body).Decode(&members)

CodePudding user response:

Not sure if you pasted the correct API output or not but it is incorrect json since it contain extra , before closing square brackets ]

{
    "members": [
        "test12",
        "test8800",
        "test0032",
        "test1234", <- extra comma
    ],
    "owners": [
        "test000",
        "test111",
        "test12",
        "test1234", <- extra comma
    ]
}

Below quotes work after removing the extra comma ,

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
)

func main() {
    const jsonStream = `{
        "members": [
            "test12",
            "test8800",
            "test0032",
            "test1234"
        ],
        "owners": [
            "test000",
            "test111",
            "test12",
            "test1234"
        ]
    }
`
    dec := json.NewDecoder(strings.NewReader(jsonStream))
    var m map[string][]string
    err := dec.Decode(&m)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%T: %v\n", m, m)

}

Playground

Note: If still the above code doesn't work then check to make sure the response Body is as posted, or you can try with interface and check the structure for testing.

  • Related