Reputation: 12378
Is there an idiomatic way in go to separate a struct from its json marshal logic?
Normally:
package models
type Foo struct {
Name `json:"full_name"`
}
But I want a separation of concerns. I don't want the json
specifying logic in the models
package with the struct, maybe put the json
logic in another serializers
package. How would you do that in idiomatic go? Maybe similar to how rails
projects handle active_model_serializers
code
Upvotes: 2
Views: 479
Reputation: 417412
It is arguable whether json
tags belong to marshaling logic or to json model. I would say specifying json tags just describe the json model and as such it may be better residing next to your Go model.
The marshaling / unmarshaling logic is implemented in the encoding/json
package itself. If you need custom logic, you can specify / implement that by implementing the json.Marshaler
and json.Unmarshaler
interfaces. This means defining methods to your type. In Go you can only specify methods to types being in the same package, so if you would separate your model from your custom parsing logic, the parsing package could not define methods to model types. Spec: Method declarations:
The type denoted by
T
is called the receiver base type; it must not be a pointer or interface type and it must be declared in the same package as the method.
That being said you would need to define your custom parsing logic on a different type, and you would need further logic to map / copy into the model type as part of the parsing logic. You would lose more than you would gain by separating the model from the parsing logic.
Going further, the struct type you marshal into may contain unexported fields which - if the parsing logic is in the same package - can be initialized properly. By separating model and logic, the logic would have troubles initializing unexported fields. One way would be to provide exported methods or functions, but then those are exported to everyone else, not just for the parsing logic.
I'd say the Go way and the easiest way is to put model and parsing logic into the same package. It still gives you a "small" separation possibility: you may put the type definition in one file (e.g. model.go
), and you may put custom parsing logic (methods implementing json.Marshaler
and json.Unmarshaler
) in another file (e.g. parse.go
) but in the same package of course, but it may be better to see a type and all its methods in one place (in one file).
Upvotes: 2