Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang - elegant way to omit a json property from being serialized

Tags:

json

go

I've got a user struct, which has sensitive fields like password:

type User struct {
    UID string `json:"uid"  binding:"required"`
    Password string `json:"password" binding:"required"`
    EmailAddress string `json:"email" binding:"required"`
}

Now I want to be able to use this struct to register a user and update, delete but also to view. What I don't want is for the password to be serialized for viewing. I can, of course, make a custom marshaller but is that the only way? I tried using the json:"-" option but that causes it to be ignored while unmarshalling as well, which I don't want. Is there a better way?

EDIT: To put some of you guys at ease, I'm NOT going to be storing the password in plaintext, of course. It's the bcrypt hash of the password, but still. I don't want it to be returned when I search for users.

like image 923
ystark Avatar asked Nov 30 '22 08:11

ystark


2 Answers

I'd say implementing json.Marshaler is the elegant solution if you want custom marshaling. It's quite simple in this case:

func (u User) MarshalJSON() ([]byte, error) {
    type user User // prevent recursion
    x := user(u)
    x.Password = ""
    return json.Marshal(x)
}

Add "omitempty" in your User type if you don't want the password field at all when marshaling.

like image 119
Peter Avatar answered Dec 04 '22 15:12

Peter


I would go with another struct and composition.

Password should never be stored in plain-text, they should be securely hashed (bcrypt, pbkdf2, etc.). That hash is the one that has to be stored and should never be serialized. By using composition, you can do something like this:

type User struct {
    UID string `json:"uid"  binding:"required"`
    HashedPassword string `json:"-"`
    EmailAddress string `json:"email" binding:"required"`
}

type UserFormData struct {
   User
   Password string `json:"password" binding:"required"`
}

This also gives you more flexibility. For instance, if you ask the user to confirm the password, you can simply change the UserFormData struct like this:

type UserFormData struct {
   User
   Password string `json:"password" binding:"required"`
   ConfirmPassword string `json:"confirm_password" binding:"required"`
}

Which also has the advantage to keep that serialization details outside your User object.

like image 34
R3v4n Avatar answered Dec 04 '22 15:12

R3v4n