Documentation ¶
Overview ¶
Out of the box, Go json (and other deserializers) cannot make a difference between JSON's `undefined` (a key is missing) and a `0`/`false`/`""`/`[]`. This means that code that uses the stdlib's default deserialization is going to inject these zero values all over the place if it receives input that is missing fields or that has misspelled field names.
This package implements an alternative deserialization.
Recommended use ¶
If you have a struct `FooSchema` that you wish to deserialize:
- To define default values for fields (in particular private fields), implement `Initializer`
func (result *FooSchema) Initialize() err { result.MyField1 = defaultValue1 result.MyField2 = defaultValue2 ... return err }
- To define a validator, implement `Validator`
func (result *FooSchema) Validator() err { if result.MyField1 > 100 { return fmt.Errorf("invalid value for MyField1!") // The error will be visible to end users. } .. return nil }
(apologies for weird formatting, please blame gofmt)
Same behavior as the standard library:
- if a struct implements `json.Unmarshaler`, short-circuit deserialization and use this method instead of anything built-in;
- lower-case field names mean that we NEVER accept external data during deserialization;
- enforces `json:"XXXX"` renamings when deserializing JSON;
- renaming with `json:"XXXX"` will not make a field public;
- a field renamed to `json:"-"` will not accept external data during deserialization.
Different behavior:
- this library also works for formats other than json, in which case instead of tag `json`, we use a specific tag (e.g. "query" or "path");
- if a value implements `Initializer`, we run the initializer before deserializing the value (this is the only way to provide default values for private fields);
- if a tag `default:"XXX"` is specified, we use this value when a field is not specified (by opposition, Go would silently insert zero values);
- if a tag `orMethod:"XXX"` is specified, we attempt to call the corresponding method when a field is not specified (by opposition, Go would silently insert zero values);
- if a tag `initialized:""` is specified, we will not complain
- if a data structure supports `Validator`, we run validation during deserialization and fail if validation rejects the value (by opposition, in Go, you need to run any validation step manually, after deserialization completes);
- we attempt to detect errors early and fail when setting up the deserializer, instead of ignoring errors and/or failing during deserialization.
Warning ¶
By design, Go will NOT let us deserialize, validate or apply default values to private fields (i.e. fields which start lower-case). This is a decision that goes deep in the language. If you have a private field, it will be initialized to its zero value unless you implement `Initializer` on the struct containing.
Index ¶
Constants ¶
const JSON = "json"
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BytesDeserializer ¶ added in v0.3.0
type BytesDeserializer[To any] interface { DeserializeString(string) (*To, error) DeserializeBytes([]byte) (*To, error) }
A deserializer from strings or buffers.
type CustomDeserializerError ¶ added in v0.2.0
type CustomDeserializerError struct { // The operation that failed, e.g. "initialize", "orMethod". Operation string // The kind of value we were applying it to, e.g. "outer", "struct", "map", "ptr", "field". Structure string // The underlying error. Wrapped error }
An error that arises because of a bug in a custom deserializer.
func (CustomDeserializerError) Error ¶ added in v0.2.0
func (e CustomDeserializerError) Error() string
Return the user-facing message.
func (CustomDeserializerError) Unwrap ¶ added in v0.2.0
func (e CustomDeserializerError) Unwrap() error
Unwrap the error.
type KVListDeserializer ¶
A deserializer from key, lists of values.
Use this to deserialize e.g. query strings.
func MakeKVListDeserializer ¶
func MakeKVListDeserializer[T any](options Options) (KVListDeserializer[T], error)
Create a deserializer from (key, value list).
type KVListReflectDeserializer ¶ added in v0.3.9
type KVListReflectDeserializer interface {
DeserializeKVListTo(kvlist.KVList, *reflect.Value) error
}
func MakeKVDeserializerFromReflect ¶ added in v0.3.6
func MakeKVDeserializerFromReflect(options Options, typ reflect.Type) (KVListReflectDeserializer, error)
type MapDeserializer ¶
type MapDeserializer[To any] interface { BytesDeserializer[To] // Deserialize a single value from a dict. DeserializeDict(shared.Dict) (*To, error) // Deserialize a list of values from a list of values. DeserializeList([]shared.Value) ([]To, error) }
A deserializers from dictionaries
Use this to deserialize e.g. JSON bodies.
func MakeMapDeserializer ¶
func MakeMapDeserializer[T any](options Options) (MapDeserializer[T], error)
Create a deserializer from Dict.
type MapReflectDeserializer ¶ added in v0.3.9
type MapReflectDeserializer interface { // Deserialize a single value from a dict. DeserializeDictTo(shared.Dict, *reflect.Value) error }
func MakeMapDeserializerFromReflect ¶ added in v0.3.6
func MakeMapDeserializerFromReflect(options Options, typ reflect.Type) (MapReflectDeserializer, error)
type Options ¶
type Options struct { // The name of tags used for renamings (e.g. "json"). // // If you leave this blank, defaults to "json". MainTagName string // Human-readable information on the nature of data // you'll be deserializing with this deserializer. // // Used for logging and error messages. // // For instance, if you're deserializing for an endpoint // "GET /api/v1/fetch", string "GET /api/v1/fetch" is an // acceptable value for RootPath. // // Optional. If you leave this blank, no human-readable // information will be added. RootPath string // An unmarshaler, used to deserialize values when they // are provided as []byte or string. Unmarshaler Unmarshaler }
Options for building a deserializer.
See also JSONOptions, QueryOptions, etc. for reasonable default values.
func JSONOptions ¶ added in v0.2.0
A preset fit for consuming JSON.
Params:
- root A human-readable root (e.g. the name of the endpoint). Used only for error reporting. `""` is a perfectly acceptable root.
func PathOptions ¶ added in v0.3.5
A preset fit for consuming Paths.
The tag name is `path`.
Params:
- root A human-readable root (e.g. the name of the endpoint). Used only for error reporting. `""` is a perfectly acceptable root.
func QueryOptions ¶ added in v0.2.0
A preset fit for consuming Queries.
The tag name is `query`.
Params:
- root A human-readable root (e.g. the name of the endpoint). Used only for error reporting. `""` is a perfectly acceptable root.