Apeasant
Apeasant

Reputation: 337

Not getting the form data sent using go

I am new to Golang and come from a python background and i am having some issues managing form requests.

I am trying to send data in form format with Go in order to mimic this curl call:

curl -X POST -k  --cacert mycert --key mykey --cert cert "https://api/v1/house?action=paint&room=hall" -F "houses=street123"

This is what i see in the API server (runs on Flask) getting the call made with curl checking headers and form information from the request.

HEADERS

Host: localhost
Connection: close
Content-Length: 152
User-Agent: curl/7.29.0
Accept: */*
Content-Type: multipart/form-data; boundary=----------------------------991133af3afb

FORM

ImmutableMultiDict([('houses', 'street123')])

When i do it using my GO code i get the following:

HEADERS

Host: localhost
Connection: close
Content-Length: 18
User-Agent: Go-http-client/1.1
Accept-Encoding: */*
Content-Type: multipart/form-data

FORM

ImmutableMultiDict([])

What I am doing:

1- I am generating a client in Generate_client for authentication with mutual tls

2- I am making my call to the API using a map[string][]string as payload and printing it before the call to ensure it has been properly constructed.

  1. I return the body and print it when calling the function.

This is my result:

Doing Form call
Params after maping:map[houses:[street123]]
FULL-URL:https://api/v1/house?action=paint&room=hall
Params encoded:&{houses=street123 0 -1}

This is my code

func Generate_client() *http.Client {
    caCert, err := ioutil.ReadFile(cacert)
    checkForErrors(err)
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    // Create key pair for certificate
    cert, err := tls.LoadX509KeyPair(cert, key)
    checkForErrors(err)
    client := &http.Client{
        Transport: &http.Transport{
            TLSClientConfig: &tls.Config{
                RootCAs: caCertPool,
                Certificates: []tls.Certificate{cert},
            },
        },
    }
    return client
}


func CallFormUrl(endpoint string, method string, dataPayload []string) string {
    fmt.Println("Doing Form call")
    FormMap := ConvertPayloadToMap(dataPayload)
    params := url.Values{}
    for key, value:= range FormMap{
        params.Add(key,value)
    }
    fmt.Println("Params after maping:"+params)

    client := Generate_client()
    fullUrl := controllerUrl+endpoint
    fmt.Println("FULL-URL:"+fullUrl)
    var ContentType string = "multipart/form-data"
    var err error
    var req *http.Request
    fmt.Println("Params encoded:"+strings.NewReader(params.Encode()))
    switch method {
    case "POST":
        req, err = http.NewRequest(http.MethodPost, fullUrl, strings.NewReader(params.Encode()))
    case "PUT":
        req, err = http.NewRequest(http.MethodPut, fullUrl, strings.NewReader(params.Encode()))
    case "GET":
        req, err = http.NewRequest(http.MethodGet, fullUrl, strings.NewReader(params.Encode()))
    case "DELETE":
        req, err = http.NewRequest(http.MethodDelete, fullUrl, strings.NewReader(params.Encode()))
    }
    req.Header.Set("Content-type", ContentType)
    checkForErrors(err)
    resp, err:= client.Do(req)
    checkForErrors(err)
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    return string(body)
}

Why the form data is not been sent?

Upvotes: 2

Views: 943

Answers (1)

mkopriva
mkopriva

Reputation: 38313

Constructing a multipart request is somewhat more verbose than constructing plain urlencoded forms, so if you need to use multipart in a lot of places you might want to abstract it away into a function that will make your life easier.

Here's an example:

params := url.Values{"houses": {"street123"}}
buf := bytes.Buffer{}
w := multipart.NewWriter(&buf)
ct := w.FormDataContentType()

h := make(textproto.MIMEHeader)
h.Set("Content-Type", "application/x-www-form-urlencoded")
if pw, err := w.CreatePart(h); err != nil {
    panic(err)
} else if _, err := pw.Write([]byte(params.Encode())); err != nil {
    panic(err)
} else if err := w.Close(); err != nil {
    panic(err)
}

r, err := http.NewRequest("POST", "https://example.com", &buf)
if err != nil {
    panic(err)
}
r.Header.Set("Content-Type", ct)

re, err := client.Do(r)
// ...

https://play.golang.org/p/nzfUjBBh7_w

Upvotes: 2

Related Questions