-2

I'm trying to develop a Terraform provider but I have a problem of the first request body. Here is the code:

type Body struct {
    id string
}

func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
    key := d.Get("key").(string)
    token := d.Get("token").(string)
    workspace_name := d.Get("workspace_name").(string)
    board_name := d.Get("board_name").(string)


    resp, err := http.Post("https://api.trello.com/1/organizations?key="+key+"&token="+token+"&displayName="+workspace_name,"application/json",nil)

    if err != nil {
            log.Fatalln(err)
    }

    defer resp.Body.Close()

    //lettura body.
    body := new(Body)
    json.NewDecoder(resp.Body).Decode(body)

    log.Println("[ORCA MADONNA] il log funzia "+body.id)
    d.Set("board_id",body.id)

    resp1, err1 := http.Post("https://api.trello.com/1/boards?key="+key+"&token="+token+"&idOrganization="+body.id+"&=&name="+board_name,"application/json",nil)
    
    if err1 != nil {
            log.Fatalln(resp1)
    }

    defer resp1.Body.Close()
    
    d.SetId(board_name)
    


    return resourceServerRead(d, m)

}

In the log is empty, but the second call have it and work fine. How is it possible?

Marco Bertelli
  • 343
  • 1
  • 9

1 Answers1

1

Go doesn't force you to check error responses, therefore it's easy to make silly mistakes. Had you checked the return value from Decode(), you would have immediately discovered a problem.

err := json.NewDecoder(resp.Body).Decode(body)
if err != nil {
    log.Fatal("Decode error: ", err)
}

Decode error: json: Unmarshal(non-pointer main.Body)

So your most immediate fix is to use & to pass a pointer to Decode():

json.NewDecoder(resp.Body).Decode(&body)

Also of note, some programming editors will highlight this mistake for you:

Decode error


Here's a working demonstration, including a corrected Body structure as described at json.Marshal(struct) returns “{}”:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "time"
)

type JSON = map[string]interface{}
type JSONArray = []interface{}

func ErrFatal(err error, msg string) {
    if err != nil {
        log.Fatal(msg+": ", err)
    }
}

func handleTestRequest(w http.ResponseWriter, req *http.Request) {
    w.Write(([]byte)("{\"id\":\"yourid\"}"))
}

func launchTestServer() {
    http.HandleFunc("/", handleTestRequest)
    go http.ListenAndServe(":8080", nil)
    time.Sleep(1 * time.Second) // allow server to get started
}

// Medium: "Don’t use Go’s default HTTP client (in production)"
var restClient = &http.Client{
    Timeout: time.Second * 10,
}

func DoREST(method, url string, headers, payload JSON) *http.Response {

    requestPayload, err := json.Marshal(payload)
    ErrFatal(err, "json.Marshal(payload")

    request, err := http.NewRequest(method, url, bytes.NewBuffer(requestPayload))
    ErrFatal(err, "NewRequest "+method+" "+url)

    for k, v := range headers {
        request.Header.Add(k, v.(string))
    }

    response, err := restClient.Do(request)
    ErrFatal(err, "DoRest client.Do")
    return response
}

type Body struct {
    Id string `json:"id"`
}

func clientDemo() {
    response := DoREST("POST", "http://localhost:8080", JSON{}, JSON{})
    defer response.Body.Close()
    var body Body
    err := json.NewDecoder(response.Body).Decode(&body)
    ErrFatal(err, "Decode")
    fmt.Printf("Body: %#v\n", body)
}

func main() {
    launchTestServer()
    for i := 0; i < 5; i++ {
        clientDemo()
    }
}
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173