func (c *Config) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error {
	logger.Info("doing config read", req.Path, req.Namespace)
	if len(req.Namespace) == 0 {
		req.Namespace = defaultNamespace
	}
	if err := namespace.AuthorizeAdmin(ctx, req.Namespace, "config.Config.Read"); err != nil {
		return err
	}
	ch, err := store.Read(req.Namespace)
	if err == store.ErrNotFound {
		return merrors.NotFound("config.Config.Read", "Not found")
	} else if err != nil {
		return merrors.BadRequest("config.Config.Read", "read error: %v: %v", err, req.Namespace)
	}
	rsp.Change = &pb.Change{
		Namespace: req.Namespace,
		Path:      req.Path,
		ChangeSet: &pb.ChangeSet{},
	}
	values := config.NewJSONValues(ch[0].Value)
	var bs []byte
	if len(req.Path) > 0 {
		bs = values.Get(req.Path).Bytes()
	} else {
		bs = values.Bytes()
	}
	dat, err := leavesToValues(string(bs), false, string(c.secret))
	if err != nil {
		return merrors.InternalServerError("config.config.Read", "Error in config structure: %v", err)
	}
	buf := new(bytes.Buffer)
	enc := json.NewEncoder(buf)
	enc.SetEscapeHTML(false)
	err = enc.Encode(dat)
	if err != nil {
		return merrors.BadRequest("config.Config.Read", "JSOn encode error: %v", err)
	}
	rsp.Change.ChangeSet.Data = strings.TrimSpace(buf.String())
	rsp.Change.ChangeSet.Format = "json"
	return nil
}
Read method is only here for backwards compatibility
package handler
import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"sync"
	pb "github.com/micro/micro/v3/proto/config"
	"github.com/micro/micro/v3/service/config"
	merrors "github.com/micro/micro/v3/service/errors"
	"github.com/micro/micro/v3/service/logger"
	"github.com/micro/micro/v3/service/store"
	"github.com/micro/micro/v3/util/auth/namespace"
)
const (
	defaultNamespace = "micro"
	pathSplitter     = "."
)
var (
	mtx sync.RWMutex
)
type Config struct {
	secret []byte
}
func NewConfig(key string) *Config {
	var dec []byte
	var err error
	if len(key) == 0 {
		logger.Warn("No encryption key provided")
	} else {
		dec, err = base64.StdEncoding.DecodeString(key)
		if err != nil {
			logger.Warnf("Error decoding key: %v", err)
		}
	}
	return &Config{
		secret: dec,
	}
}
func (c *Config) Get(ctx context.Context, req *pb.GetRequest, rsp *pb.GetResponse) error {
	if len(req.Namespace) == 0 {
		req.Namespace = defaultNamespace
	}
	if err := namespace.AuthorizeAdmin(ctx, req.Namespace, "config.Config.Get"); err != nil {
		return err
	}
	ch, err := store.Read(req.Namespace)
	if err == store.ErrNotFound {
		return merrors.NotFound("config.Config.Get", "Not found")
	} else if err != nil {
		return merrors.BadRequest("config.Config.Get", "read error: %v: %v", err, req.Namespace)
	}
	var secret bool
	if req.GetOptions().GetSecret() {
		secret = true
	}
	rsp.Value = &pb.Value{}
	values := config.NewJSONValues(ch[0].Value)
	var bs []byte
	if len(req.Path) > 0 {
		bs = values.Get(req.Path).Bytes()
	} else {
		bs = values.Bytes()
	}
	dat, err := leavesToValues(string(bs), secret, string(c.secret))
	if err != nil {
		return merrors.InternalServerError("config.config.Get", "Error in config structure: %v", err)
	}
	buf := new(bytes.Buffer)
	enc := json.NewEncoder(buf)
	enc.SetEscapeHTML(false)
	err = enc.Encode(dat)
	if err != nil {
		return merrors.BadRequest("config.Config.Get", "JSOn encode error: %v", err)
	}
	rsp.Value.Data = strings.TrimSpace(buf.String())
	return nil
}