func (b *Backend) Unmarshal(ctx context.Context, to interface{}) error {
	f, err := os.Open(b.path)
	if err != nil {
		if b.optional {
			return backend.ErrNotFound
		}
		return errors.Wrapf(err, "failed to open file at path \"%s\"", b.path)
	}
	defer f.Close()
	switch ext := filepath.Ext(b.path); ext {
	case ".json":
		err = json.NewDecoder(f).Decode(to)
	case ".yml":
		fallthrough
	case ".yaml":
		err = yaml.NewDecoder(f).Decode(to)
	case ".toml":
		_, err = toml.DecodeReader(f, to)
	default:
		err = errors.Errorf("unsupported extension \"%s\"", ext)
	}
	return errors.Wrapf(err, "failed to decode file \"%s\"", b.path)
}
Unmarshal takes a struct pointer and unmarshals the file into it,
using either json or yaml based on the file extention.
package file
import (
	"context"
	"encoding/json"
	"os"
	"path/filepath"
	"github.com/BurntSushi/toml"
	"github.com/heetch/confita/backend"
	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)
type Backend struct {
	path     string
	name     string
	optional bool
}
func NewBackend(path string) *Backend {
	name := filepath.Ext(path)
	if name != "" {
		name = name[1:]
	}
	return &Backend{
		path: path,
		name: name,
	}
}
func NewOptionalBackend(path string) *Backend {
	name := filepath.Ext(path)
	if name != "" {
		name = name[1:]
	}
	return &Backend{
		path:     path,
		name:     name,
		optional: true,
	}
}