how do i create a post request like this in golang [closed] - http

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 months ago.
Improve this question
Hi guys a have a question about POST REQUEST
I have a some python code like this
data = {
"name": "Frank",
"age": 21,
"nationality": ["Britan"],
}
r = requests.post('somesite', json=data)
How i can make a POST requst similar this on GOLANG, i tried use "nationality": ["Britan"]
but i have a some errors with []
i tried to use map[string]string but ofc its not working
May be i can use some structure to resolve my problem

maybe you should use map[string]interface{}
or you can also use strings.NewReader to send request directly
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "http://localhost:8080"
method := "POST"
payload := strings.NewReader(`{
"name": "Flank",
"age": 21,
"nationality": ["Britan"]
}`)
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Content-Type", "application/json")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}

You should use map[string]interface{} instead of map[string]string
As this link (https://go.dev/blog/maps):
map[KeyType]ValueType
where KeyType may be any type that is comparable, and ValueType may be any type at all, including another map!
Your body has both string and slice type, so ValueType is interface{} better than string.

Related

How to get data from external api using GO? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 months ago.
Improve this question
I have external data I need to get data from it and this result from an API endpoint
{
"data": [
{
"id": 30002005,
"name": "test",
"info": "{"Version":"7.0.484","CompanyName":"test"}",
},
......
]
}
I need to get this data and reformat it to my case (put the data into struct then do whatever i need).
The go code:
type OldData struct {
Id string `json:"id"`
Name string `json:"name"`
}
func Index() {
url := "https://exmaple.com/api/posts"
var bearer = "Bearer XXXXXX"
req, err := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", bearer)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
}
var record OldData
json.Unmarshal(body, &record)
fmt.Println(record)
}
The result of fmt.Println(record) is { }
Update
I create thrid for info :
type OldData struct {
Id string `json:"id"`
Name string `json:"name"`
Info string `json:"info"`
}
type Info struct {
Version string `json:"Version"`
CompanyName string `json:"CompanyName"`
}
In the JSON there is an array, named data. You're trying to unmarshal it to a single struct. Try to define a struct which has a data field which is a slice:
type OldData struct {
Id string `json:"id"`
Name string `json:"name"`
}
type OldDataItems struct {
Data []OldData `json:"data"`
}
Now try to unmarshal into an instance of OldDataItems.

Http POST request with body Go

I want to construct a HTTP POST request with a body using Go net/http library.
The function I am using to construct the http request is the following: docs
http.NewRequest(method string, url string, body io.Reader)
I came up with 2 solutions, but I am trying to see which one is more idiomatic and extensible to support different body configurations.
Solution #1
bytesObj := []byte(`{"key":"value"}`)
body := bytes.NewBuffer(bytesObj)
Solution #2
bodyMap := map[string]string{"key":"value"}
bodyBytes, _ := json.Marshal(bodyMap)
body := bytes.NewBuffer(bodyBytes)
Ideally, I will move the code to a helper function that way I can customize the construction of the body. The helper function will be something like
func constructBody(someArgument) io.Reader {
return bodyHere
}
If the body is already string, options #1 is more compelling to me.
If you are only working with a key -> value with only string, option #2 is better.
But this will become cumbersome when you have nested struct
But most of the time in my experience we are dealing with struct. I like to make the struct closer to where the http call happened.
func main() {
ctx := context.Background()
body := struct {
Key string `json:"key"`
}{
Key: "value",
}
out, err := json.Marshal(body)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", "http://example.com", bytes.NewBuffer(out))
if err != nil {
log.Fatal(err)
}
req = req.WithContext(ctx)
http.DefaultClient.Do(req)
}
And if the struct is used in multiple places, you can make a package level struct.
To have it more reusable, you could create a jsonReaderFactory, which just takes a few lines of code:
func jsonReaderFactory(in interface{}) (io.Reader, error) {
buf := bytes.NewBuffer(nil)
enc := json.NewEncoder(buf)
err := enc.Encode(in)
if err != nil {
return nil, fmt.Errorf("creating reader: error encoding data: %s", err)
}
return buf, nil
}
Example on playground

How to access http client response body global [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
In the code below, am trying to access the variable "Regprofile" as global variable but and getting empty output. Any help?
type GMLCInstance struct {
NfInstanceID string `json:"nfInstanceID"`
HeartBeatTimer int `json:"heartBeatTimer"`
NfType []string `json:"nfType"`
NfStatus []string `json:"nfStatus"`
Ipv4Addresses []string `json:"ipv4Addresses"`
}
var Regprofile GMLCInstance
// Request credentials and token from NRF and register profile to NFR database
func init() {
urlcred := "https://127.0.0.1:9090/credentials"
// Perform the request
resp, err := netClient.Get(urlcred)
if err != nil {
log.Fatalf("Failed get: %s", err)
}
defer resp.Body.Close()
// Fill the record with the data from the JSON
var cr Credential
// Use json.Decode for reading streams of JSON data
if err := json.NewDecoder(resp.Body).Decode(&cr); err != nil {
log.Println(err)
}
//fmt.Println(cr)
clientId := cr.CLIENTID
clientsec := cr.CLIENTSECRET
// Get token
reqtoken := url.Values{
"grant_type": []string{"client_credentials"},
"client_id": []string{clientId},
"client_secret": []string{clientsec},
"scope": []string{"GMLC"},
}
urlq := "https://127.0.0.1:9090/oauth2/token?"
res, err := netClient.PostForm(urlq+reqtoken.Encode(), nil)
if err != nil {
log.Fatalf("Failed get: %s", err)
}
var auth AccessToken
// Use json.Decode for reading streams of JSON data
if err := json.NewDecoder(res.Body).Decode(&auth); err != nil {
log.Println(err)
}
//fmt.Println(auth.AccessToken)
token := auth.AccessToken
para := url.Values{
"access_token": []string{token},
}
//============================================================
// Register GMLC Instance to NRF, PUT
var gmlc = []byte(`{
"nfInstanceID": "f81d4fae-7dec-11d0-a765-00a0c91egmlc",
"heartBeatTimer": 0,
"nfType": ["GMLC"],
"nfStatus": ["string"],
"ipv4Addresses": ["172.16.0.X:5000"]
}`)
//================= Registser profile to NRF ========================//
postnrf := "https://127.0.0.1:9090/nnrf-nfm/v1/nf-instances/f81d4fae-7dec-11d0-a765-00a0c91egmlc?"
rq, err := http.NewRequest("PUT", postnrf+para.Encode(), bytes.NewBuffer(gmlc))
rq.Header.Set("Content-Type", "application/json")
rq.Header.Set("Accept", "application/json")
response, err := netClient.Do(rq)
if err != nil {
panic(err)
}
defer res.Body.Close()
decoder := json.NewDecoder(response.Body)
var Regprofile GMLCInstance
err = decoder.Decode(&Regprofile)
if err != nil {
fmt.Println("Response body not well decoded")
}
fmt.Println(Regprofile)
}
The output of fmt.Println(Regprofile) gives
{f81d4fae-7dec-11d0-a765-00a0c91egmlc 10 [GMLC] [REGISTERED] [172.16.0.X:5000]}
However, when i print the variable in for example main as
func main(){
fmt.Println(Regprofile)
}
I get empty data as
{ 0 [] [] []}
In func init() you redeclare variables var Regprofile GMLCInstance locally to function scope. This declaration shadows global variable with local one. Just delete this local declaration inside init().

Golang *bytes.Buffer nil causes fatal error [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I had the same issue as https://github.com/golang/go/issues/26666 because I have a wrap function for my http requests.
Sometimes I need to request:
body := new(bytes.Buffer)
json.NewEncoder(body).Encode(h)
req("POST", "http://example.com", body)
And sometimes it's simply:
req("GET", "http://example.com", nil)
runtime error: invalid memory address or nil pointer dereference
I ended up with:
req("GET", "http://example.com", new(bytes.Buffer))
But I'm not sure if it's the right thing to do.
The function:
func req(method string, url string, body *bytes.Buffer) int {
req, err := http.NewRequest(method, url, body)
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(user, psw)
resp, err := client.Do(req)
checkErr(err)
if resp.StatusCode > 500 {
time.Sleep(30 * time.Second)
resp, err = client.Do(req)
checkErr(err)
}
defer resp.Body.Close()
return resp.StatusCode
}
Updated function:
func req(method string, url string, body io.Reader) int {
req, err := http.NewRequest(method, url, body)
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(user, psw)
resp, err := client.Do(req)
checkErr(err)
defer resp.Body.Close()
if resp.StatusCode >= 500 {
time.Sleep(30 * time.Second)
req, err := http.NewRequest(method, url, body)
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(user, psw)
resp, err := client.Do(req)
checkErr(err)
defer resp.Body.Close()
}
return resp.StatusCode
}
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
The body in http.NewRequest() is optional, so passing nil is acceptable when you're doing GET requests.
The problem is that the body parameter of http.NewRequest is an interface type: io.Reader, and you're attempting to pass a value of a concrete type *bytes.Buffer. What happens is that this nil pointer will be wrapped in a non-nil interface value, and that will be passed to http.NewRequest as the body.
If you don't have a body, pass nil explicitly, like this:
func req(method string, url string, body *bytes.Buffer) int {
var bodyToPass io.Reader
if body != nil {
bodyToPass = body
}
req, err := http.NewRequest(method, url, bodyToPass)
// ....
}
And then you can call it like:
req("GET", "http://example.com", nil)
Although best would be if your req() function would take io.Reader in the first place, so you don't have to check its value explicitly:
func req(method string, url string, body io.Reader) int {
req, err := http.NewRequest(method, url, body) // You may pass it as-is
// ....
}
And you can call it with nil or with a non-nil *bytes.Buffer too:
req("GET", "http://example.com", nil) // OK
req("POST", "http://example.com", bytes.NewBufferString("data")) // Also OK
For more details, see Hiding nil values, understanding why golang fails here

Golang Struct as Payload for POST Request

New to golang. I'm trying to make a POST request to an auth endpoint to get back a token for authing further requests. Currently the error I'm getting is missing "credentials". I've written the same logic in Python so I know what I am trying to do is what the system is expecting.
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/cookiejar"
"os"
)
type Auth struct {
Method string `json:"credentials"`
Email string `json:"email"`
Password string `json:"password"`
Mfa string `json:"mfa_token"`
}
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Email: ")
e, _ := reader.ReadString('\n')
fmt.Print("Enter Password: ")
p, _ := reader.ReadString('\n')
fmt.Print("Enter 2FA Token: ")
authy, _ := reader.ReadString('\n')
auth := Auth{"manual", e, p, authy}
j, _ := json.Marshal(auth)
jar, _ := cookiejar.New(nil)
client := &http.Client{
Jar: jar,
}
req, err := http.NewRequest("POST", "https://internaltool.com/v3/sessions", bytes.NewBuffer(j))
if err != nil {
log.Fatal(err)
}
req.Header.Add("Accept-Encoding", "gzip, deflate, br")
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
s := string(body)
if res.StatusCode == 400 {
fmt.Println("Bad Credentials")
fmt.Println(s)
return
}
}
The question is - am I properly marshalling the AUTH struct into JSON and adding it appropriately to the POST request? As the API is not even seeing the credentials key in the JSON I think I must be doing something wrong. Anything helps.
Here's a minimum viable example of using json.Marshal to convert a Struct to a JSON object in the context of a POST request.
Go's standard libraries are fantastic, there is no need to pull in external dependencies to do such a mundane thing.
func TestPostRequest(t *testing.T) {
// Create a new instance of Person
person := Person{
Name: "Ryan Alex Martin",
Age: 27,
}
// Marshal it into JSON prior to requesting
personJSON, err := json.Marshal(person)
// Make request with marshalled JSON as the POST body
resp, err := http.Post("https://httpbin.org/anything", "application/json",
bytes.NewBuffer(personJSON))
if err != nil {
t.Error("Could not make POST request to httpbin")
}
// That's it!
// But for good measure, let's look at the response body.
body, err := ioutil.ReadAll(resp.Body)
var result PersonResponse
err = json.Unmarshal([]byte(body), &result)
if err != nil {
t.Error("Error unmarshaling data from request.")
}
if result.NestedPerson.Name != "Ryan Alex Martin" {
t.Error("Incorrect or nil name field returned from server: ", result.NestedPerson.Name)
}
fmt.Println("Response from server:", result.NestedPerson.Name)
fmt.Println("Response from server:", result.NestedPerson.Age)
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
// NestedPerson is the 'json' field of the response, what we originally sent to httpbin
type PersonResponse struct {
NestedPerson Person `json:"json"` // Nested Person{} in 'json' field
}
As http.Client is relatively a low-level abstraction, gorequest(https://github.com/parnurzeal/gorequest) as an alternative is strongly recommended.
headers, queries, and body can be posted in any type, which is a bit more like what we often do in Python.

Resources