Closed apoggi-carecloud closed 1 year ago
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Any update on this? Or any workaround about the omitempty tag?
I just wrote the omitempty tags via code generation to the files
@apoggi-carecloud Does you write a plugins to add omitempty tag? Or you wrote the omitempty tags to the files after code generation?
Omit per field could be a be a usefull feature - if the models are marshalled for internal usage. The generated marshaling to match a graphql query returns empty things. It has no external effect if a struct attribute is marked with omitempty tag, if the attribute is marked with an ! in the schema and therefore is not generated as a pointer. I prefer using no pointers especially for strings (to avoid the nasty two step instantiation) and mark everything with a !. I reuse the generated models for typesafe db ops and add typesafe validation (via ozzo) to them in another file, which is not overwritten by the generator. usually i add the omitempty tags to every model (and do other additions and custom renamings (like adding a dot in the json name etc.) via a small script like (example only for adding all omitempty tags), which is automatically called after every new model generation:
path := "models/models_gen.go"
read, err := ioutil.ReadFile(path)
if err != nil {
panic(err)
}
newContents = strings.Replace(newContents, "\"`", ",omitempty\"`", -1)
err = ioutil.WriteFile(path, []byte(newContents), 0)
if err != nil {
panic(err)
}
Let's re-open this - omitempty is important for marshaling structs to JSON to send in a request. Lots of APIs have a default value for a field, but if you marshal a struct with an empty field right now, it'll use the default value (like an empty string), which will override the API's default.
I only need use model_gen hook = https://gqlgen.com/recipes/modelgen-hook/
let's say you have gqlgen.yml
in root dir, then create a file called runner_model_gen.go
in runner_model_gen.go
:
package main
import (
"fmt"
"github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/plugin/modelgen"
"os"
"strings"
)
func mutateHook(b *modelgen.ModelBuild) *modelgen.ModelBuild {
for _, model := range b.Models {
for _, field := range model.Fields {
// this is the logic to add omitempty
omit := strings.TrimSuffix(field.Tag, `"`)
field.Tag = fmt.Sprintf(`%v,omitempty"`, omit)
}
}
return b
}
func main() {
cfg, err := config.LoadConfigFromDefaultLocations()
if err != nil {
fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
os.Exit(2)
}
p := modelgen.Plugin{
MutateHook: mutateHook,
}
err = api.Generate(cfg,
api.NoPlugins(),
api.AddPlugin(&p),
)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(3)
}
}
then run them
go run runner_model_gen.go
check your model_gen.go
then u can see the result, enjoy:)
I was looking for this as a feature of gqlgen and stumbled upon this issue. And I found myself wondering why it might not have been implemented (personally I like omitempty). But when I thought about it, when you have omitempty, it would be odd for someone to have a query:
{
people {
name
nickname
}
}
And get back something like:
{
"data": {
"people": [
{
"name": "Stephen",
"nickname": "Steve"
},
{
"name": "Joe"
}
]
}
}
instead of something like
{
"data": {
"people": [
{
"name": "Stephen",
"nickname": "Steve"
},
{
"name": "Joe",
"nickname": null
}
]
}
}
Especially given that your query directly asks for it. So maybe in the graphql world, it is good to return back the empty value of the field.
But then again, some empty values, like for bools and ints, could be deceptive by returning falses and 0s (nvm, that is what the pointers are for lol)
Thoughts?
This causes default values for input types not to be applied.
input Foo {
principalType: PrincipalType = User
}
enum PrincipalType {
User
Org
}
type Foo struct {
PrincipalType *PrincipalType `json:"principalType" yaml:"principalType"`
}
//...
func (ec *executionContext) unmarshalInputFoo(ctx context.Context, obj interface{}) (model.Foo, error) {
var it model.Foo
var asMap = obj.(map[string]interface{})
if _, present := asMap["principalType"]; !present {
asMap["principalType"] = "User"
}
I'm re-using the models internally and I wanted the possibility to add omitempty
since I'm marshalling the objects into maps to send to other APIs.
However for my scenario it can be achieve with a simple solution.
Minor example:
func cleanPayload(properties *model.UserProperties) (map[string]interface{}, error) {
marshaled, err := json.Marshal(payload)
if err != nil {
return nil, err
}
mapped := make(map[string]interface{})
err = json.Unmarshal(marshaled, &mapped)
if err != nil {
return nil, err
}
for key, val := range mapped {
if val == nil {
delete(mapped, key)
}
}
return mapped, nil
}
It's working for us, hope it helps.
Instead of having to manually define models with the 'omitempty' json tag, it would be great if we could pass that through the yaml config file.