deserialize

package
v0.3.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2024 License: Apache-2.0 Imports: 11 Imported by: 0

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.

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

View Source
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

type KVListDeserializer[To any] interface {
	DeserializeKVList(kvlist.KVList) (*To, error)
}

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

func JSONOptions(root string) Options

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

func PathOptions(root string) Options

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

func QueryOptions(root string) Options

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.

type Unmarshaler added in v0.2.0

type Unmarshaler shared.Driver

Directories

Path Synopsis
Code specific to deserializing JSON.
Code specific to deserializing JSON.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL