Skip to content

Instantly share code, notes, and snippets.

@sparr
Created June 13, 2023 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sparr/008ebfab065bd00c3dd903fa43b9ad55 to your computer and use it in GitHub Desktop.
Save sparr/008ebfab065bd00c3dd903fa43b9ad55 to your computer and use it in GitHub Desktop.
golang proposal for standard tag functionality for json, toml, yaml, etc
This gist is to preserve this proposal draft while I pursue alternate proposals first.
Currently if a package wants to define a struct that can be loaded from arbitrary config files, with encoded/serialized/markup field names different from the struct field names (e.g. changing "FooBar" to "foo_bar" to match conventions, "Miscellaneous" to "misc" for brevity, etc), the package must add separate struct tags for json, toml, yaml, etc. Any encoding not specifically enumerated in the tags will either fall back to using the struct fields directly, or have to implement parsing of another encoding's tags.
While these different encoding packages offer some unique functionality, such as go-yaml's `inline`, encoding/json's `string`, and go-toml's `multiline`, they all share common functionality of specifying the key name and the `omitempty` flag. For use cases where that subset of functionality is sufficient, it would be convenient if most or all of the markup/encoder/serializer/marshaler/etc packages supported a common tag syntax.
My proposal is for a standard tag that looks and works like the existing tag syntax for toml, json, and yaml, but with a new name. Something like "markup" or "encoded" or "serialized", preferably relatively short, possibly even the empty string (i.e. the equivalent of `json:"foo"` would be `:"foo"`.
With this proposal, and support by the relevant packages, the following code:
```golang
type Platform struct {
ArchitectureType string `toml:"arch_type" json:"arch_type" yaml:"arch_type"`
// ...
}
```
might be replaced with this:
```golang
type Platform struct {
Architecture string `serialized:"arch"`
// ...
}
```
Each of the packages could still read its own tag, for both unique and common functionality, with the following proposed conflict resolution behavior:
* Specifying a field name in both the new common tag and the package tag would result in the package tag overriding the common tag.
* Specifying a boolean flag (e.g. `omitempty`) in the common tag but not the package tag would result in the flag still being applied; packages would need to provide an inverse flag (e.g. `keepempty`) to override this behavior.
I anticipate that handling of this new tag could be exported functionality of encoding/json that could be used by the other packages, but that is not a necessary component of this proposal. The implementation of that functionality could be left to the individual packages, or may end up in a third party package like https://pkg.go.dev/github.com/fatih/structtag.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment