Skip marshalling field in Go - json

Hi how would I skip marshalling the Data property in this example?
Once I receive this response, I have to parse this data property as JSON in my frontend because it has been remarshalled. I would like everything to be ready to use from the Go backend. I'm not sure how to do this. Or perhaps I can update the main unmarshaled response with the unmarshaled Data so I don't get this issue; not sure how to do this.
Get response from API and unmarshal it
Get another API response based on "Data"
Unmarshal "Data" and update it
Marshal updated "Data" and update original response
Final marshal to send to client
Generic Example:
res, err := ... // from API
type Response struct {
Id string
Data string
}
var response Response
json.Unmarshal([]byte(res), &response)
res, err = ... // fetch additional data based on response
var data map[string]interface{} // Data may have unknown properties
json.Unmarshal([]byte(res), &data)
data["knownproperty"] = "changed"
json, _ := json.Marshal(data)
data := string(json)
// update original response
response.Data = data
// marshal to send to client
json, _ = json.Marshal(response)
data = string(json)
fmt.Fprintf(w, "%v", data)
Thanks

Related

How to convert json to string in golang and echo framework?

I have a json that I receive by post
{"endpoint": "assistance"}
I receive this like this
json_map: = make (map[string]interface{})
Now I need to assign it to a variable as a string but I don't know how to do it.
endpoint: = c.String (json_map ["endpoint"])
A type safe way to do this would be creating a struct that represents your request object and unmarshalling it.
This gives you a panic on unexpected requests.
package main
import (
"encoding/json"
"fmt"
)
type response struct {
Endpoint string
}
func main() {
jsonBody := []byte(`{"endpoint": "assistance"}`)
data := response{}
if err := json.Unmarshal(jsonBody, &data); err != nil {
panic(err)
}
fmt.Println(data.Endpoint)
}
// assistance
This program as an example safely decodes the JSON into a struct and prints the value.
What you are trying to achieve is not to convert a JSON to a string but an empty interface interface{} to a string You can achieve this by doing a type assertion:
endpoint, ok := json_map["endpoint"].(string)
if !ok {
// handle the error if the underlying type was not a string
}
Also as #Lex mentionned, it would probably be much safer to have a Go struct defining your JSON data. This way all your fields will be typed and you will no longer need this kind of type assertion.

golang unmarshall unknown json data

I have a use case where I need to unmarshal response from HTTP requests. I don't know the response format ahead of time but would just like to return the result upstream to web client (similar functionality to a proxy)
Normally I would just unmarshal like the following:
resp, _ = http.Post(url, "application/json", bytes.NewBuffer(jsonPayload))
body, _ := ioutil.ReadAll(resp.Body)
responseJson := make(map[string]interface{})
json.Unmarshal(body, &responseJson)
However, if the result is instead an array of JSON [{},{}...]
then I would need to do the following
var responseList []map[string]interface{}
json.Unmarshal([]byte(body), &responseList)
And if the result is a single string value like "ok" it would also require different unmarshaling methods
But If I don't know the response type ahead of time, how would I know how to unmarshal?
You can just unmarshall it as interface like :
var responseJson interface{}
json.Unmarshal(body, &responseJson)
To read the type of response:
switch resp := responseBody.(type) {
case string:
fmt.Println(resp)
case float64:
fmt.Println(int(resp))
default:
fmt.Println(resp)
}

Post request to Golang API to send JSON and stringy-fied JSON

While making a POST request to Golang API, if I send stringy-fied JSON data it returns success but when I send JSON data it returns error with status 403.
Please help me understanding this behavior and how can I send JSON data using a POST request method.
File: main.go
package main
import (
"devmgmtv2/auth"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"log"
"net/http"
)
func main() {
router := mux.NewRouter()
auth.AuthInit(router)
ssid.SsidInit(router)
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
router.HandleFunc("/auth/login", Login).Methods("POST", "OPTIONS")
log.Fatal(http.ListenAndServe(":8000", handlers.CORS(headersOk, originsOk, methodsOk)(router)))
}
func Login(w http.ResponseWriter, r *http.Request) {
//Create User Struct
var user User
json.NewDecoder(r.Body).Decode(&user)
userPassword := getUserPassword(user.User)
// call get value for that user
// check for equality if true, return the structure
// if false return error
if user.Password == userPassword {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("success"))
} else {
http.Error(w, "Forbidden", http.StatusForbidden)
}
}
When sending JSON to any http server you always have to use JSON.stringify().
Not doing so will result in sending [object Object]...
There are client libraries that do this kind of heavy lifting for you, but behind the scenes the JSON is always send as a string.
Node.JS handles it the same way... it receives the string representation and usually something like body parser is run on the incoming request to extract the JSON from the string. So it might happen here behind the scenes, but it still happens.

go-json-rest: JSON payload is empty

I'm trying to use go-json-rest to create RESTful APIs
I have this model struct:
type Todo struct {
id int
name string
}
And I am trying to do a POST request to create an object of Todo type:
func CreateTodo(w rest.ResponseWriter, r *rest.Request) {
body, _ := ioutil.ReadAll(r.Body)
log.Println("body content is: ", string(body)) // here I can see {"name": "test1"}
var todo Todo = Todo{}
err := r.DecodeJsonPayload(&todo) // here the error shows JSON payload is empty
defer r.Body.Close()
if err != nil {
log.Println("error in parsing json")
rest.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if todo.name == "" {
rest.Error(w, "todo name is required", 400)
return
}
lock.Lock()
var nextId int = len(todos)
// todos[nextId] = todo
todo.id = nextId // set its id
todos = append(todos, todo)
log.Println("num of todos: ", len(todos))
lock.Unlock()
w.WriteJson(&todo)
}
However, in the console of the POSTMAN client, the error shows:
{
"Error": "JSON payload is empty"
}
I was wondering where might go wrong. Thanks
Edit:
This should not be considered a duplicate question, because I am not even trying to use the json package to do marshalling/unmarshalling of JSON object. Instead I am using the rest.Request object (built in go-json-rest) to decode the json parameters as posted from client.
After much digging and search on this problem I found this answer below resolved my issue:
body, _ := ioutil.ReadAll(r.Body) will consume everything from the
request body. So after removing this line, the json parsing works!
I was just being silly doing body, _ := ioutil.ReadAll(r.Body) before decoding the JSON parameters without really understanding what ioutil.ReadAll() does to the request body.
As I quoted above in the edited post, ioutil.ReadAll() consumes everything in the request body, leaving nothing for the json decoder to parse. After removing the line body, _ := ioutil.ReadAll(r.Body), the json parsing works as expected.

Passing JSON parameter to function in GOLANG

I want to pass a JSON object to a function in GOLANG ,so how would I define my parameters,would it be fine if I can define my params as string .below is a sample
func getDetailedNameSpace(authentication string,id string) string{
var jsonStr = []byte(string);
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
req, _ := http.NewRequest("PUT", "https://"+authentication.endPoint+"/object/namespaces/"+id, bytes.NewBuffer(jsonStr))
req.Header.Add("X-Sds-Auth-Token",authentication.authtoken)
req.Header.Add("Accept","application/json")
res,err:=client.Do(req)
body, err := ioutil.ReadAll(res.Body)
if err!=nil{
fmt.Printf("%s",err)
}
return string(body);
}
Also i have to validate the params ,as in python we can have like below
def getDetailedNameSpace(authentication,id=None):
assert authentication!=None,"Authentication Required"
I'm assuming you're trying to put the JSON as the body of your PUT request. In this case you'll just want to use assignment. The request object has a field of type io.ReadCloser for it.
req.Header.Add("Accept","application/json")
req.Body = bytes.NewBufferString(MyJsonAsAString)
res,err:=client.Do(req)
There are some other methods like http.Post which take the body as an argument but in this case, the Do method takes a Request object as an argument and that has a property for the Body.