Provider

GoDoc Build Status codecov.io

Provider is a go package that allows to use different sources to unmarshal or marshal a struct.

It allows to use a structure with Provider and Value and treat the value according to the provider specified.

List of default providers

Static provider

Static Provider expects athe value to be the JSON itself.

{
    "provider": "static",
    "value": {
        "some": "json"
    }
}

URL provider

URL Provider requires the value to be an URL, will execute the HTTP request and use the response body for the unmarshal.

{
    "provider": "url",
    "value": "http://example.com/content"
}

Create your own provider

You can create your own using the Provider interface:

type Provider interface {
	Set(data []byte, v interface{}) error
}

You need to register it with a unique name using:

func Register(name string, p Provider)

Usage

It allows to use helpers in the JSON methods to use the package capabilities. A type can use a Field, or a struct containing several of them in the methods. Each Field will use the given provider.

// Field is an helper used to inject Value
type Field struct {
    Name string
	Ptr  *interface{}
}

Field has a name, which is used for error message, and a pointer to the interface used for marshal and unmarshal.

Let’s take the following type, which returns a structure with two fields:

type A struct {
	Str string `json:"str,omitempty"`
	Int int    `json:"int,omitempty"`
}

func (a *A) toFields() interface{} {
	type A struct {
		Str *provider.Field `json:"str,omitempty"`
		Int *provider.Field `json:"int,omitempty"`
	}
	return &A{
		Str: provider.NewField("str", &a.Str),
		Int: provider.NewField("int", &a.Int),
	}
}

func (a *A) MarshalJSON() ([]byte, error) { 
	return json.Marshal(a.toFields())
}

func (a *A) UnmarshalJSON(v []byte) error { 
	return json.Unmarshal(v, a.toFields())
}

It will use a provider for each field, decoding the following JSON:

{
    "str": {
        "provider": "static",
        "value": "banana"
    },
    "int": {
        "provider": "static",
        "value" :42
    }
}

This other one uses just one provider for the structure itself. It requires to create a private type to strip the methods from the structure.

type B A

func (b *B) toFields() interface{} {
	type stripped B // strips methods, avoids recursion
	return provider.NewField("b", (*stripped)(b))
}

func (b *B) MarshalJSON() ([]byte, error) {
	return json.Marshal(b.toFields())
}

func (b *B) UnmarshalJSON(v []byte) error {
	return json.Unmarshal(v, b.toFields())
}

It will result in a JSON that looks like the following:

{
    "provider": "static",
    "value": {
        "str": "banana",
        "int": 42
    }
}