Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to disallow unknown fields when unmarshaling JSON #1368

Closed
mbarnes opened this issue May 28, 2024 · 3 comments
Closed

Option to disallow unknown fields when unmarshaling JSON #1368

mbarnes opened this issue May 28, 2024 · 3 comments

Comments

@mbarnes
Copy link

mbarnes commented May 28, 2024

I would like the option to fail on unknown JSON fields when unmarshaling the generated model types.

Typically, one would do this in Go by substituting json.Unmarshal(data, targetPtr) with:

decoder = json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
return decoder.Decode(targetPtr)

However this doesn't work for the generated model types because they implement their own UnmarshalJSON method that use a switch statement for struct field names with no "default" case. For example, take this generated method:

// UnmarshalJSON implements the json.Unmarshaller interface for type Example.
func (e *Example) UnmarshalJSON(data []byte) error {
	var rawMsg map[string]json.RawMessage
	if err := json.Unmarshal(data, &rawMsg); err != nil {
		return fmt.Errorf("unmarshalling type %T: %v", e, err)
	}
	for key, val := range rawMsg {
		var err error
		switch key {
		case "apple":
				err = unpopulate(val, "Apple", &e.Apple)
			delete(rawMsg, key)
		case "banana":
				err = unpopulate(val, "Banana", &e.Banana)
			delete(rawMsg, key)
		case "pear":
				err = unpopulate(val, "Pear", &e.Pear)
			delete(rawMsg, key)
		}
		if err != nil {
			return fmt.Errorf("unmarshalling type %T: %v", e, err)
		}
	}
	return nil
}

What I would like to see, when failure on unknown fields is desired, is a "default" case in the switch statement that returns an error.

This would likely require a new CLI switch, maybe initially for but not limited to Go code generation.

@jhendrixMSFT
Copy link
Member

There's a switch, disallow-unknown-fields, that should do what you want (off by default). Can you please try it?

@mbarnes
Copy link
Author

mbarnes commented May 29, 2024

Indeed, that looks like it does exactly what I need.
Apologies, I didn't know to look there for additional options. The Go flags list in the main autorest repo could use a link to more options.

@mbarnes mbarnes closed this as completed May 29, 2024
@jhendrixMSFT
Copy link
Member

Best way to see the per-code generator settings is as follows (substitute the version of the code generator you're using).

autorest --use=@autorest/go@4.0.0-preview.66 --go --help

The --go switch "activates" the generator so you'll get its help as part of the output.

Go Generator (activated by --go)

  --module=<string>             The name of the Go module written to go.mod.  Omit to skip go.mod generation.
  --azcore-version=<string>     Semantic version of azcore without the leading 'v' to use if different from the default version (e.g. 1.2.3).
  --file-prefix=<string>        Optional prefix to file names. For example, if you set your file prefix to "zzz", all generated code files will begin with "zzz".
  --module-version=<string>     When --azure-arm is true, semantic version to include in generated telemetryInfo constant without the leading 'v' (e.g. 1.2.3).
  --group-parameters=<boolean>  Enables parameter grouping via x-ms-parameter-grouping, defaults to true.
  --stutter=<string>            Uses the specified value to remove stuttering from types and funcs instead of the built-in algorithm.
  --honor-body-placement=<boolean>  When true, optional body parameters are treated as such for PATCH and PUT operations.
  --remove-non-reference-schema=<boolean>  When true, non-reference schema will be removed from the generated code.
  --normalize-operation-name=<boolean>  When true, add suffix for operation with unstructured body type and keep original name for operation with structured body type. When false, keep original name if only one body type, and add suffix for operation with non-binary body type if more than one body type.
  --rawjson-as-bytes=<boolean>  When true, properties that are untyped (i.e. raw JSON) are exposed as []byte instead of any or map[string]any. The default is false.
  --generate-fakes=<boolean>    When true, enables generation of fake servers. The default is false.
  --slice-elements-byval=<boolean>  When true, slice elements will not be pointer-to-type. The default is false.
  --head-as-boolean             When true, HEAD requests will return a boolean value based on the HTTP status code. The default is false, but will be set to true if --azure-arm is true.
  --generate-fakes              Enables generation of fake servers. The default value is set to the value of --azure-arm.
  --inject-spans                Enables generation of spans for distributed tracing. The default value is set to the value of --azure-arm.
  --single-client=<boolean>     Indicates package has a single client. This will omit the Client prefix from options and response types. If multiple clients are detected, an error is returned.
  --disallow-unknown-fields=<boolean>  When true, unmarshalers will return an error when an unknown field is encountered in the payload.
  --fix-const-stuttering=<boolean>  When true, fix stuttering for const types and their values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants