This question already has answers here:
How to read multiple times from same io.Reader
(5 answers)
Closed 4 years ago.
type ValidationModel struct {
Name string `json:"name" valid:"alpha,required~Name is required"`
Email string `json:"email" valid:"email~Enter a valid email.,required~Email is required."`
Password string `json:"password" valid:"required~Password is required"`
}
validationModel := ValidationModel{}
json.NewDecoder(r.Body).Decode(&validationModel)
_, err := govalidator.ValidateStruct(validationModel)
First I am validating the request body using govalidator.
type UserModel struct {
ID bson.ObjectId `json:"_id" bson:"_id"`
Name string `json:"name" bson:"name"`
Email string `json:"email" bson:"email"`
Password string `json:"password,omitempty" bson:"-"`
PasswordHash string `json:"-" bson:"passwordHash"`
Salt string `json:"-" bson:"salt"`
Token string `json:"token,omitempty" bson:"-"`
}
user := models.UserModel{}
json.NewDecoder(r.Body).Decode(&user)
fmt.Println(user)
And after validating the request, again I am decoding the request body into user struct, but the request body has been read once using validationModel, so when I try to again decode it into user, it is not giving me any values.
I can think of two solutions here:
Store request body in one separate variable, and use that variable two times.
Copy validationModel values in user.
But I don't have any idea about to implement these approaches and which approach is best to follow. Or is there any other solution which can be implemented?
Thanks in advance.
Storing the data can be easily done with ioutil.ReadAll():
data, err := ioutil.ReadAll(r.Body)
If you need the data back as a io.Reader (which is how the r.Body is), then you can use bytes.NewReader():
reader := bytes.NewReader(data)
And ACTUALLY, r.Body is a io.ReadCloser, so if you need that you can use ioutil.NopCloser() in conjunction with bytes.NewReader():
reader := ioutil.NopCloser(bytes.NewReader(data))
Related
This question already has an answer here:
Convert byte slice to io.Reader
(1 answer)
Closed 2 months ago.
I have a body response that I can only get Byte responses. This bytes encode a csv-like response. Something like:
element_a,element_b,element_c
cooper,claus,active
carlos,saldanha,inactive
robert,jesus,active
Lets say then that I have the struct that looks like this:
type ESResponse struct {
ElementA string `csv:"element_a"`
ElementB string `csv:"element_b"`
ElementC string `csv:"element_c"`
}
I would like to unmarshal the byte response so then I'm able to access its elements.
What I've been doing is the following:
var actualResult ESResponse
body := util.GetResponseBody() // this is where the byte response comes from.
in := string(body[:]) // here I transform it to a string but I trully think this is not the best way.
err = gocsv.Unmarshal(in, &actualResult)
I've been using this library here: https://pkg.go.dev/github.com/gocarina/gocsv#section-readme but I'm unable to understand the error I get which is:
cannot use in (variable of type string) as io.Reader value in argument to gocsv.Unmarshal: string does not implement io.Reader (missing method Read)
It means, that in argument must implement interface io.Reader, but you argument's type is string, which doesn't. So if you want to deserialize value from string, you can do this:
body := `
element_a,element_b,element_c
cooper,claus,active
carlos,saldanha,inactive
robert,jesus,active`
var actualResult []ESResponse
in := strings.NewReader(body)
err := gocsv.Unmarshal(in, &actualResult)
or gocsv.Unmarshal(bytes.NewReader([]byte(body)), &actualResult) to deserialize from bytes array
This question already has answers here:
How can we read a json file as json object in golang
(2 answers)
Closed 7 months ago.
What I want to achieve
I'm parsing IAM Policies in Go. In IAM Policies, most of the fields can be either a string or an array of strings. It's hard to think these decision trees in my head what I want is kind of exhaustive pattern matching.
What I did
I loeded a policy with json.Unmarshal
type Policy struct {
Version string `json:"Version"`
Id string `json:"ID,omitempty"`
Statements []Statement `json:"Statement"`
}
type Statement struct {
// ...
Action interface{} `json:"Action"` // string or array
// ...
}
And iterating over statements.
switch ele := st.Action.(type) {
case string:
action, _ := expandAction(ele, data)
actions = append(actions, action...)
setter(i, actions)
case []string:
for _, a := range ele {
if strings.Contains(a, "*") {
exps, _ := expandAction(a, data)
actions = append(actions, exps...)
} else {
actions = append(actions, a)
}
setter(i, actions)
fmt.Println(actions)
}
default:
// interface{}
}
The Problem
It always goes to the default case.
Can use reflection, but don't think I really should, since runtime could know types when json.Unnarshal is called.
As you can see from the official document the type for JSON array is []interface. If you update []string to []interface then you can run the related case block. However, if you have to sure that is array of string, reflection can provide it.
I have a "createUser" function on a Go server in which I hash a new user's password and store their data from a form sent via POST.
The database of users and their stats is pulled up and converted into a string map containing structs with their info. It looks like this:
var userStruct struct {
Users map[string]struct {
Admin, Moderator, Root bool
Pass *string
}
}
The reason it is a pointer is because later on I might want to change the password.
So, when I create a new user I unmarshal the JSON from the POST request into a struct like this:
var newUser struct{
Username, Password string
IsAdmin, IsModerator bool
}
I use json.NewDecoder to decode it into the struct as follows:
err := json.NewDecoder(r.Body).Decode(&newUser)
Then, I hash it and store the results using sha, json.MarshalIndent and ioutil.WriteFile:
sha := sha1.New()
sha.Write([]byte(newUser.Password))
var hashedPass string;
hashedPass = hex.EncodeToString(sha.Sum(nil))
fmt.Println(hashedPass)
userStruct.Users[newUser.Username] = struct {
Admin, Moderator, Root bool
Pass *string
}{
Admin: newUser.IsAdmin,
Moderator: newUser.IsModerator,
Root: false,
Pass: &hashedPass,
}
fmt.Println(*userStruct.Users[newUser.Username].Pass)
file, _ := json.MarshalIndent(userStruct, "", " ")
_ = ioutil.WriteFile("userInfo.json", file, 0644)
Then, on the login side, I convert the string slice of the parsed form of the credentials to a byte slice and compare the username/password to the ones stored in the database.
here, which shows that I can use the Gob encoder:
r.ParseForm()
sha := sha1.New()
buf := &bytes.Buffer{}
gob.NewEncoder(buf).Encode(r.Form["password"])
bufBytes := buf.Bytes()
sha.Write(bufBytes)
bs := sha.Sum(nil)
fmt.Println(hex.EncodeToString(bs))
usrJSON, _ := ioutil.ReadFile("userInfo.json")
var userStruct struct {
Users map[string]struct {
Root, Admin, Moderator bool
Pass *string
}
}
json.Unmarshal(usrJSON, &userStruct)
username := strings.ToLower(strings.Join(r.Form["username"], "")
I then compare the username and the password. The password comparing is the only problem we need to focus on, though:
if *userStruct.Users[username].Pass == hex.EncodeToString(bs) {
}
Attempting to debug, I outputted the results of the hashing in both the user creation function, and the user login function.
The password I used for an example is myverysecretpassword.
The stored hash looks like this:
7816b9b6485dd785aab9f91a31a0b80997ed44b9
The password attempt looks like this:
08618c3225370a2205d698d06df48ba4b820c1d4
As I look deeper and deeper into this, I realize that it might be my usage of pointers/addresses, but I'm still confused anyways.
What is going on?
It looks like I didn't quite understand this at the bottom of the answer on the post about converting string slices to byte slices:
Gob is simple and to the point. However, the format is only readable with other Go code.
Reading it a couple of times makes sense, Go encoding isn't meant to convert a string slice directly to a byte slice.
According to the comments, Gob is an encoder, not a string slice to byte slice converter.
I can use http.Request.Form.Get("key") instead, to get the data as a string and convert it into bytes using []byte().
This question already has answers here:
Lowercase JSON key names with JSON Marshal in Go
(4 answers)
Closed 5 years ago.
I'm a new user converting an application to Go. I have something like the following which is working:
type Network struct {
Ssid string
Security string
Bitrate string
}
func Scan(w http.ResponseWriter, r *http.Request) {
output := runcmd(scripts+"scan.sh", true)
bytes := []byte(output)
var networks []Network
json.Unmarshal(bytes, &networks)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(networks)
}
The problem is the old version didn't use capitals on the json variables returned.
I want the front-end to see ssid not Ssid. If I make the attributes in the struct lowercase the code no longer works as they become unexported variables.
When the field names in your struct do not match the json field names, you can use field tags.
eg:
Ssid string `json:"myOtherFieldName"`
Please read the json docs for more details.
This tool very convenient for learning:
https://mholt.github.io/json-to-go/
Give it example of JSON that you want it will recommend golang.
e.g. JSON
{
"ssid": "some very long ssid",
"security": "big secret",
"bitrate": 1024
}
will suggest golang:
type AutoGenerated struct {
Ssid string `json:"ssid"`
Security string `json:"security"`
Bitrate int `json:"bitrate"`
}
now you can change AutogGenerated, Ssid, Security, Bitrate to whatever you want.
This question already has answers here:
Lowercase JSON key names with JSON Marshal in Go
(4 answers)
Closed 5 years ago.
What I am trying to do
I am parsing a JSON HTTP response based on this answer to a similar question. My code is able to parse the JSON without any error but is unable to read the values and store them in the provided variable.
This has been puzzling me for the last 2 hours and it might be due to a trivial reason that I am overlooking here.
CODE
type ImporterResponse struct {
results []packagemeta `json:"results"`
}
type packagemeta struct {
path string `json:"path"`
synopsis string `json:"synopsis,omitempty"`
count int `json:"import_count,omitempty`
}
func main() {
res := []byte(`{"results":[{"path":"4d63.com/randstr/lib/randstr","import_count":0,"synopsis":"Package randstr generates random strings (e.g."},{"path":"bitbucket.org/pcas/tool/mathutil","import_count":0}]}`)
fmt.Println("Decoding the JSON")
r := bytes.NewReader(res)
decoder := json.NewDecoder(r)
packageimporters := &ImporterResponse{}
err := decoder.Decode(packageimporters)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Packageimporters: %+v", packageimporters)
fmt.Println(len(packageimporters.results))
}
Link to Playground: https://play.golang.org/p/NzLl7Ujo2IJ
What I want:
How to fix this?
Why is no error message raised if JSON is not parsed properly?
P.S: I understand that this question has been asked before and there are possible solutions available but none of them work for me. Hence, I have made this post.
You need to make your struct fields exported, otherwise the json package cannot access them.
Please read JSON and go for more details, specifically this paragraph:
The json package only accesses the exported fields of struct types
(those that begin with an uppercase letter). Therefore only the the
exported fields of a struct will be present in the JSON output.
And this one for more details:
How does Unmarshal identify the fields in which to store the decoded
data? For a given JSON key "Foo", Unmarshal will look through the
destination struct's fields to find (in order of preference):
An exported field with a tag of "Foo" (see the Go spec for more on
struct tags),
An exported field named "Foo", or
An exported field
named "FOO" or "FoO" or some other case-insensitive match of "Foo".
So your struct should really be:
type Packagemeta struct {
Path string `json:"path"`
Synopsis string `json:"synopsis,omitempty"`
Count int `json:"import_count,omitempty`
}