Reputation: 337
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.
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
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