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

  1. Store request body in one separate variable, and use that variable two times.

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

sohamdodia
  • 357
  • 1
  • 4
  • 11
  • 1
    In your case, you should re-factor to not read the body twice. It would be far more efficient (especially if you have large bodies), to validate the decoded data _after_ you have decoded it, rather than decoding twice. – Jonathan Hall Nov 18 '18 at 09:05
  • @Flimzy Can you please explain how can I refactor the code? I have another approach as well in which I can copy data of one struct into another. How can I do that? – sohamdodia Nov 18 '18 at 09:43
  • In general: Don't have a separate 'ValidationModel'--instead, validate the `UserModel`. – Jonathan Hall Nov 19 '18 at 08:11

1 Answers1

17

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))
poy
  • 10,063
  • 9
  • 49
  • 74
  • 4
    It's not a good idea to use ioutil.ReadAll when r.Body is very large, such as 1G Bytes. – iwind Apr 24 '19 at 01:47
  • 1
    This is true, however you can protect yourself with a https://golang.org/pkg/io/#LimitedReader – poy Aug 21 '20 at 00:18