I extend your example by making it more general, and I show an elegant solution to the more general problem.
Let's assume that in User there are:
- some fields that must be parsed only from the input
- some fields that must appear only in the output
- and there are some fields that must be parsed from input and must also appear in output
Your example is a "subset" of this (as in your example there are no common fields).
This can be elegantly solved without repeating fields using embedding. You may create 3 separate types; one for the common fields UserBoth, one for the input-only fields UserIn, and one for the output-only fields UserOut:
type UserBoth struct {
Name string `json:"name"`
Age int `json:"age"`
}
type UserIn struct {
*UserBoth
Email string `json:"email"`
}
type UserOut struct {
*UserBoth
ID uint `json:"id"`
}
Note that UserBoth (or rather *UserBoth to avoid duplicating the struct value) is embedded in both UserIn and UserOut, because we want those fields in both.
Now if you have an input that contains all fields (even though we don't want all):
const in = `{"name":"Bob","age":23,"Email":"[email protected]","id":123}`
Unmarshaling into a value of UserIn will only parse what you want:
uin := UserIn{UserBoth: &UserBoth{}}
err := json.Unmarshal([]byte(in), &uin)
fmt.Printf("%+v %+v %v\n", uin, uin.UserBoth, err)
Output (note that the Email field is parsed but ID isn't):
{UserBoth:0x1050e150 Email:[email protected]} &{Name:Bob Age:23} <nil>
And when you want to generate output:
uout := UserOut{UserBoth: uin.UserBoth}
// Fetch / set ID from db:
uout.ID = 456
out, err := json.Marshal(uout)
fmt.Println(string(out), err)
Output (note that the ID field is present but Email isn't):
{"name":"Bob","age":23,"id":456} <nil>
Try it on the Go Playground.
Having a "unified" User
The above example used 2 different structs: UserIn for parsing and UserOut to generate the output.
If inside your code you want to use a "unified" User struct, this is how it can be done:
type User struct {
UserIn
UserOut
}
Using it:
uboth := &UserBoth{}
u := User{UserIn{UserBoth: uboth}, UserOut{UserBoth: uboth}}
err := json.Unmarshal([]byte(in), &u.UserIn)
fmt.Printf("%+v %+v %v\n", u, u.UserIn.UserBoth, err)
// Fetch / set ID from db:
u.ID = 456
out, err := json.Marshal(u.UserOut)
fmt.Println(string(out), err)
Try this one on the Go Playground.