Identify valid struct fileds

type StructName struct {
Width uint `json:"width,omitempty"`
bWidth bool `json:"bwidth,omitempty"`
Height uint `json:"height,omitempty"`
bHeight bool `json:"bheight,omitempty"`
Name string `json:"name,omitempty"`
Place string `json:"place,omitempty"`

}

In the above struct, we could use POST with request body as below
{"width":5,"height":10,"bheight":true,"place":"wonderland"}

the other fields take their default values after ‘json.unmarshal’ . How would we know/identify only the tags/fields sent by POST. Suppose the default values are also valid values how to distinguish the values explicitly set using POST.

Other blogs i referred suggesting using custom marshler to work around this, but since we have only basic datatypes is there something already built in GO to identify this ?

Thanks

You cannot, using value types and the standard unmarshaller. The zero value of a string is "" and you cannot tell if this came as an empty string in the actual JSON data or if it was missing in the JSON data. You can distinguish it by using pointers:

type Foo {
  Bar *string
  Baz *string
}

If you unmarshal {"Bar":""} into this the result will be that the Bar field contains a non-nil pointer to a string with the value "" while the Baz field contains a nil pointer. This is however somewhat cumbersome as now you need to deal with pointers and potential nil values all the time, leading to GetBar() string methods, anger, and hate.

Another option is to initialize the fields to some sentinel value that will never occur in the actual data.

type Foo {
  Bar string
  Baz string
}
result := Foo{
  Bar: "<invalid>",
  Baz: "<invalid>",
}
json.Unmarshal(..., &result)

Any fields still set to "<invalid>" were not present in the JSON data.

A third option is to unmarshal into map[string]interface{} and see what keys you got.

A fourth option is to use a custom unmarshaller that keeps track of which fields it saw during unmarshalling or, if you use custom types for the fields, have them implement UnmarshalJSON and set a bool if they were unmarshalled correctly. Compare for example database/sql.NullString an similar for how that approach works (there used to handle database nulls).

(Also, note that your fields must be exported, i.e, begin with a capital letter, for the JSON unmarshaller to be able to see them. Your example has some unexported fields.)

1 Like

Thank you Jakob for the reply.

I did use the option of using map[string]interface{} ,it does require us to validate for if nil != Foo["Bar"] , so with a lot of struct fields , the validation will go on for each of struct fields. This is the down side of this approach I thought.

With regard to using UnmarshalJSON , i found and tried an example like this

You can also use something like https://github.com/clbanning/checkjson#MissingJSONKeys() - that’ll give you a list of struct fields that will NOT be set by the JSON object. If you’ve initialized the struct before unmarshaling the JSON object; that’ll also be the list of fields that have default values.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.