我正在使用terraform sdk创建一个自定义terraform提供程序.我正在try 从现有的API GET调用读取数据.我发现很难将JSON响应从API映射到terraform模式.这是我的数据源架构:

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,
      },
    },
  }
}

这是API JSON响应:

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

这是我的数据源读取函数

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
}

我一直在犯这样的错误:

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",
  ])
}

Go相关问答推荐

Go Net/http路由

如何将泛型函数作为参数传递给golang中的另一个函数?

在Golang中,@LATEST和@UPGRADE特殊查询有什么不同?

Golang应用程序:所请求的资源上不存在HTTP-Control-Allow-Origin标头

困扰围棋官方巡回赛的S建议所有方法都使用同一类型的接收器

Go Regexp:匹配完整的单词或子字符串,或者根本不匹配

允许在 struct 中使用复合作为函数参数

golang有int32溢出吗?

Golang内置打印(Ln)函数&S行为怪异

如何在Golang中覆盖404

Go 1.20 中如何计算连接错误?

不接受来自 stdin 的重复输入

在 Go 中使用 Apache Arrow 按时间间隔对事件进行分区

同一文件上的多个 Arrow CSV 阅读器返回 null

如何在切片增长时自动将切片的新元素添加到函数参数

如何在没有内存分配的情况下压缩和发布文件

不理解切片和指针

手动将 OpenTelemetry 上下文从 golang 提取到字符串中?

Golang LinkedList 删除第一个元素

在 Go 泛型中,如何对联合约束中的类型使用通用方法?