I have a User struct with a password field. When I'm creating a user (or udpating with a new password) via POSTed JSON, I want to accept/unmarshal the password field into my object, but whenever I return a user, I want to omit the password field. Below is the best I've been able to come up with so far. It works, but it requires a lot of duplication around the field names that I'd like to eliminate (right now, if I add a new field like FirstName
, I have to add that in 3 separate places).
How do I do this better while still honoring the json
tags on the struct?
func main() {
origJson := []byte(`{"id":"1","username":"Chad","pwd":"sillypants"}`)
fmt.Println("Original: " + string(origJson))
var unmarshalled User
json.Unmarshal(origJson, &unmarshalled)
fmt.Printf("Unmarshalled: %+v\n", unmarshalled)
marshalled, _ := json.Marshal(unmarshalled)
fmt.Println("ReMarshalled: " + string(marshalled))
}
type User struct {
Id string `json:"id"`
Username string `json:"username"`
Password string `json:"pwd"`
}
type SafeUser struct {
Id string `json:"id"`
Username string `json:"username"`
}
func (u User) MarshalJSON() ([]byte, error) {
safeUser := SafeUser{
Id : u.Id,
Username: u.Username,
}
return json.Marshal(safeUser)
}
Try it on the Go Playground
Take advantage of embedded structs. Define a User, and embed that in an UnsafeUser which adds the password field (and anything else, like payment info).
type User struct {
Id string `json:"id"`
Username string `json:"username"`
}
type UnsafeUser struct {
User
Password string `json:"pwd"`
}
(It's better to make things safe by default and declare what is unsafe, like Go's unsafe pacakge.)
Then you can extract the User from within the UnsafeUser without having to know and copy all the fields.
func (uu UnsafeUser) MarshalJSON() ([]byte, error) {
return json.Marshal(uu.User)
}
$ go run ~/tmp/test.go
Original: {"id":"1","username":"Chad","pwd":"sillypants"}
Unmarshalled: {User:{Id:1 Username:Chad} Password:sillypants}
ReMarshalled: {"id":"1","username":"Chad"}
Note how you can see the User struct embedded within the unmarshalled UnsafeUser.
I had the same issue but came across this article.
The idea is to use embedding and an anonymous struct to override fields.
func (u User) MarshalJSON() ([]byte, error) {
type Alias User
safeUser := struct {
Password string `json:"pwd,omitempty"`
Alias
}{
// Leave out the password so that it is empty
Alias: Alias(u),
}
return json.Marshal(safeUser)
}
Try it
The Alias helps prevent an infinite loop while marshalling.
Please note that you have to maintain the same JSON field name for the override to work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With