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
server.go
package main
import (
"log"
"net/http"
)
func main() {
s := `
{
"members": [
"test12",
"test8800",
"test0032",
"test1234"
],
"owners": [
"test000",
"test111",
"test12",
"test1234"
]
}
`
http.HandleFunc("/projects", func(w http.ResponseWriter, _ *http.Request) {
log.Println("Getting Projects")
w.WriteHeader(http.StatusOK)
w.Write([]byte(s))
})
log.Println("Listening...")
log.Fatal(http.ListenAndServe(":8000", nil))
}
data_source_projects.go
package hashicups
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/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,
},
},
}
}
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/projects", "http://localhost:8000"), nil)
if err != nil {
return diag.FromErr(err)
}
r, err := client.Do(req)
if err != nil {
return diag.FromErr(err)
}
defer r.Body.Close()
var projects map[string]interface{}
err = json.NewDecoder(r.Body).Decode(&projects)
if err != nil {
return diag.FromErr(err)
}
if err := d.Set("members", projects["members"]); err != nil {
return diag.FromErr(err)
}
if err := d.Set("owners", projects["owners"]); err != nil {
return diag.FromErr(err)
}
// always run
d.SetId(strconv.FormatInt(time.Now().Unix(), 10))
return diags
}
Output:
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
project = {
"id" = "1651575329"
"members" = tolist([
"test12",
"test8800",
"test0032",
"test1234",
])
"owners" = tolist([
"test000",
"test111",
"test12",
"test1234",
])
}