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

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.

Related

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

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.

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 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.

Unable to unmarshal JSON array in Golang

I am getting the below response in a URL and I want to unmarshal it, but I am unable to do so.
This is the kind of response that I'd like to unmarshal.
[
{"title": "Angels And Demons", "author":"Dan Brown", "tags":[{"tagtitle":"Demigod", "tagURl": "/angelDemon}] }
{"title": "The Kite Runner", "author":"Khalid Hosseinei", "tags":[{"tagtitle":"Kite", "tagURl": "/kiteRunner"}] }
{"title": "Dance of the dragons", "author":"RR Martin", "tags":[{"tagtitle":"IronThrone", "tagURl": "/got"}] }
]
I am trying to unmarshal this sort of response but not being able to do so. This is the code that I am trying to write.
res, err := http.Get(url)
if err != nil {
log.WithFields(log.Fields{
"error": err,
}).Fatal("Couldn't get the html response")
}
defer res.Body.Close()
b, err := ioutil.ReadAll(res.Body)
if err != nil {
log.WithFields(log.Fields{
"error": err,
}).Fatal("Couldn't read the response")
}
s := string(b)
var data struct {
Content []struct {
Title string `json:"title"`
Author string `json:"author"`
Tags map[string]string `json:"tags"`
}
}
if err := json.Unmarshal([]byte(s), &data); err != nil {
log.WithFields(log.Fields{
"error": err,
}).Error("Un-marshalling could not be done.")
}
fmt.Println(data.Content)
Can anyone please help me in this regard?
Thanks in advance.
Change it
var data struct {
Content []struct {
Title string `json:"title"`
Author string `json:"author"`
Tags map[string]string `json:"tags"`
} }
to this
type Content struct {
Title string `json:"title"`
Author string `json:"author"`
Tags map[string]string `json:"tags"`
}
var data []Content
Consider unmarshalling it into a slice of Content:
type Content struct {
Title string `json:"title"`
Author string `json:"author"`
Tags map[string]string `json:"tags"`
}
// Send in your json
func convertToContent(msg string) ([]Content, error) {
content := make([]Content, 0, 10)
buf := bytes.NewBufferString(msg)
decoder := json.NewDecoder(buf)
err := decoder.Decode(&content)
return content, err
}
Check out an example with your use case here: http://play.golang.org/p/TNjb85XjpP
I was able to sort out this issue by doing a simple amendment in the above code.
var Content []struct {
Title string `json:"title"`
Author string `json:"author"`
Tags map[string]string `json:"tags"`
}
Thanks for all your responses.

Resources