equivalent to curl --data in go http request payload - go

For the purpose of setting a K/V in a NoSQL storage, I need to create an equivalent to the following curl command in go:
curl -H "Content-Type: text/xml" --data '[...]' http://localhost:8000/test/testrow/test:testcolumn
I am trying to use something in the lines of the following code for that purpose, although I am unable to find how to set the binary data []byte(value) as a POST payload.
func setColumn(table string, key string, col string, value string) {
url := "http://localhost:8123/" + table + "/" + key + "/" + col
req, err := http.NewRequest("POST", url, nil)
req.Header.Set("Content-Type", "application/octet-stream")
data = []byte(value)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
So, how to map the data payload within the POST request ? Any indicators are welcome.

In order to post any data you should pass the value instead of nil
in the Newrequest method.
This should work
func setColumn(table string, key string, col string, value string) {
url := "http://localhost:8123/" + table + "/" + key + "/" + col
**data := bytes.NewReader([]byte(value))**
req, err := http.NewRequest("POST", url, **data**)
req.Header.Set("Content-Type", "application/octet-stream")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
Most of the NoSQL Servers has GO API use them instad of creating your own HTTP request.

Related

How to read from array json response in Go

I have an API request that returns a refresh_token inside array, which looks something like this:
[
{
"refresh_token" : "C61551CEA183EDB767AA506926F423B339D78E2E2537B4AC7F8FEC0C29988819"
}
]
I need to access this refresh_token's value, and use it to query another API.
To do this, I'm attempting to first 'ReadAll' the response body, and then access the key inside of it by calling 'refreshToken'.
However, it's not working. Does anyone know how to resolve this as I can't figure it out?
Here's my code:
func Refresh(w http.ResponseWriter, r *http.Request) {
client := &http.Client{}
// q := url.Values{}
fetchUrl := "https://greatapiurl.com"
req, err := http.NewRequest("GET", fetchUrl, nil)
if err != nil {
fmt.Println("Errorrrrrrrrr")
os.Exit(1)
}
req.Header.Add("apikey", os.Getenv("ENV"))
req.Header.Add("Authorization", "Bearer "+os.Getenv("ENV"))
resp, err := client.Do(req)
if err != nil {
fmt.Println("Ahhhhhhhhhhhhh")
os.Exit(1)
}
respBody, _ := ioutil.ReadAll(resp.Body)
fmt.Println(respBody["refresh_token"])
w.WriteHeader(resp.StatusCode)
w.Write(respBody)
}
If you do not need it as custom type you can cast it as []map[string]string
respBody, _ := ioutil.ReadAll(resp.Body)
var body []map[string]string
json.Unmarshal(respBody, &body)
fmt.Println(body[0]["refresh_token"])

how to call graphql resolver inside go code

I tried this code
url := "http://142.77.221.41:8000/graphql"
query := `{
hello(theme:"HELLO WORLD", html: "<h1>hello</h1>", recipientList: "hello#mail.ua") {theme, html, recipientList}
}`
body := strings.NewReader(`{"query":` + query + `}`)
//json := `{"query":` + strconv.QuoteToASCII(query) + `}`
req, err := http.NewRequest("POST", url, body)
if err != nil {
fmt.Println(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
it sends
500 Internal Server Error
but when I go to the http://142.77.221.41:8000/graphql and type the same query on playground it works fine

How to send new request with object instead of bytes?

I need to send an object of data e.g. {hello: "world", goodbye: "world"} to an API. I'm doing it like this right now:
inputs := form.GetElementsByTagName("input")
var data = make(map[string]interface{}) // after adding values this looks like this: {hello: "world", goodbye: "world"}
for value := range inputs {
// Append all values from the inputs to a new array, with the key named by the input name attribute
if inputs[value] != nil && inputs[value].(*dom.HTMLInputElement).Value != "" {
data[inputs[value].(*dom.HTMLInputElement).Name] = inputs[value].(*dom.HTMLInputElement).Value
}
}
parsedData, _ := json.Marshal(data)
req, _ := http.NewRequest(method, url, bytes.NewBuffer(parsedData))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
go func() { // Must be a goroutine
response, _ := client.Do(req)
defer response.Body.Close()
}()
The problem I'm having is since we're sending it as a byte, the server always returns error responses as it's expecting to deal with an object.
How can I make sure it's sending an object instead of bytes?
You are setting the content type to application/x-www-form-urlencoded while you are sending the data in json format, so change your content-type when setting the request headers, along with that do not skip the error to check what is the error returned:
parsedData, err := json.Marshal(data)
if err != nil{
fmt.Println(err)
}
req, err := http.NewRequest(method, url, parsedData) // send the parseData which are bytes returned from the marshal.
if err != nil{
fmt.Println(err)
}
req.Header.Set("Content-Type", "application/json") // set the content type to json
go func() { // Must be a goroutine
response, err := client.Do(req)
if err != nil{
fmt.Println(err)
}
defer response.Body.Close()
}()
// you should check for response status to verify the details as
fmt.Println("response Status:", response.Status)
fmt.Println("response Headers:", response.Header)
body, _ := ioutil.ReadAll(response.Body)
fmt.Println("response Body:", string(body))
One thing that should be taken into consideration is that you have not exported your struct fields. That can be the reason your json string becomes empty. Make your struct fields exportable by making their first letter of each field in caps.
I solved this using the "net/url" package.
data := url.Values{}
for value := range inputs {
// Append all values from the inputs to a new array, with the key named by the input name attribute
if inputs[value] != nil && inputs[value].(*dom.HTMLInputElement).Value != "" {
data.Add(inputs[value].(*dom.HTMLInputElement).Name, inputs[value].(*dom.HTMLInputElement).Value)
}
}
req, _ := http.NewRequest(method, actionUrl, strings.NewReader(data.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

Sending octet stream

I have two go programs - one running as a server daemon, the other being executed manually. I want to be able to send a request to the server from the other program, sending some binary data there via post request. How can I do this?
I know I can send a string like this:
data := url.Values{}
data.Set("req", buf)
u, _ := url.ParseRequestURI(domain)
u.Path = path
urlStr := fmt.Sprintf("%v", u)
client := &http.Client{}
r, _ := http.NewRequest("POST", urlStr, bytes.NewBufferString(data.Encode()))
r.Header.Add("Authorization", "auth_token=\"XXXXXXX\"")
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
resp, _ := client.Do(r)
return resp.Status
But I want to send an octet-stream which I can then read from ioutil.ReadAll(r.Body).
The following show how to send data inside the request body to a server, and read it on the server side. The client part is as follow:
c := http.Client{}
data := []byte("This is a content that will be sent in the body")
r, err := http.NewRequest("POST", "http://localhost:8080", bytes.NewBuffer(data))
// You should never ignore the error returned by a call.
if err != nil {
panic(err)
}
c.Do(r)
And in your http.Handler function:
d, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
fmt.Println("Request content : ", string(d))
This is the easiest way.

Basic HTTP Auth in Go

I'm trying to do basic HTTP auth with the code below, but it is throwing out the following error:
2013/05/21 10:22:58 Get mydomain.example: unsupported protocol scheme ""
exit status 1
func basicAuth() string {
var username string = "foo"
var passwd string = "bar"
client := &http.Client{}
req, err := http.NewRequest("GET", "mydomain.example", nil)
req.SetBasicAuth(username, passwd)
resp, err := client.Do(req)
if err != nil{
log.Fatal(err)
}
bodyText, err := ioutil.ReadAll(resp.Body)
s := string(bodyText)
return s
}
Any idea what I may be doing wrong?
the potential 'gotcha' is if your website does any redirects... Go-lang will drop your specified headers on the redirects. (I had to do wireshark to see this! You can quicky find out in chrome by right-clicking then "inspect element" and click network tab)
you'll want to define a redirect function that adds the header back in.
func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}
func redirectPolicyFunc(req *http.Request, via []*http.Request) error{
req.Header.Add("Authorization","Basic " + basicAuth("username1","password123"))
return nil
}
func main() {
client := &http.Client{
Jar: cookieJar,
CheckRedirect: redirectPolicyFunc,
}
req, err := http.NewRequest("GET", "http://localhost/", nil)
req.Header.Add("Authorization","Basic " + basicAuth("username1","password123"))
resp, err := client.Do(req)
}
You need to specify the protocol for NewRequest, e.g. "http://", see here.
req, err := http.NewRequest("GET", "http://mydomain.example", nil)

Resources