func (s *Manager) SaveMockAPI(ctx context.Context, request *v1alpha1.SaveMockAPIRequest) (*v1alpha1.SaveMockAPIResponse, error) {
	api := request.GetData()
	if api == nil {
		return nil, errors.New("api is nil")
	}
	var encoder jsonpb.Marshaler
	data, err := encoder.MarshalToString(api)
	if err != nil {
		return nil, err
	}
	if err := s.storage.Set(ctx, api.GetUniqueKey(), data); err != nil {
		return nil, err
	}
	return &v1alpha1.SaveMockAPIResponse{}, nil
}
SaveMockAPI is used to create or update MockAPI
package apimanager
import (
	"context"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"sync"
	"github.com/golang/protobuf/jsonpb"
	"github.com/gorilla/mux"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/pflag"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"github.com/bilibili-base/powermock/apis/v1alpha1"
	"github.com/bilibili-base/powermock/pkg/interact"
	"github.com/bilibili-base/powermock/pkg/pluginregistry"
	"github.com/bilibili-base/powermock/pkg/pluginregistry/storage/memory"
	"github.com/bilibili-base/powermock/pkg/util"
	"github.com/bilibili-base/powermock/pkg/util/logger"
)
type Provider interface {
	v1alpha1.MockServer
	MockResponse(ctx context.Context, request *interact.Request) (*interact.Response, error)
	Start(ctx context.Context, cancelFunc context.CancelFunc) error
}
type Manager struct {
	cfg *Config
	storage        pluginregistry.StoragePlugin
	pluginRegistry pluginregistry.Registry
	mux *mux.Router
	apis map[string]*v1alpha1.MockAPI
	lock sync.RWMutex
	v1alpha1.UnimplementedMockServer
	registerer prometheus.Registerer
	logger.Logger
}
type Config struct {
	GRPCAddress string
	HTTPAddress string
}
func NewConfig() *Config {
	return &Config{
		GRPCAddress: "0.0.0.0:30000",
		HTTPAddress: "0.0.0.0:30001",
	}
}
func (c *Config) RegisterFlagsWithPrefix(prefix string, f *pflag.FlagSet) {
	f.StringVar(&c.GRPCAddress, prefix+"apiManager.grpcAddress", c.GRPCAddress, "gRPC service listener address")
	f.StringVar(&c.HTTPAddress, prefix+"apiManager.httpAddress", c.HTTPAddress, "http service listener address")
}
func (c *Config) Validate() error {
	if c.HTTPAddress == "" && c.GRPCAddress == "" {
		return errors.New("[apiManager] grpcAddress and httpAddress cannot be empty at the same time")
	}
	return nil
}
func New(cfg *Config,
	pluginRegistry pluginregistry.Registry,
	logger logger.Logger, registerer prometheus.Registerer) (Provider, error) {
	service := &Manager{
		cfg:            cfg,
		registerer:     registerer,
		pluginRegistry: pluginRegistry,
		mux:            mux.NewRouter(),
		apis:           map[string]*v1alpha1.MockAPI{},
		Logger:         logger.NewLogger("apiManager"),
	}
	return service, nil
}
func (s *Manager) Start(ctx context.Context, cancelFunc context.CancelFunc) error {
	if err := s.setupStorage(); err != nil {
		return err
	}
	if err := s.loadAPIs(ctx); err != nil {
		return err
	}
	if err := s.setupGRPCServer(ctx, cancelFunc); err != nil {
		return err
	}
	if err := s.setupHTTPServer(ctx, cancelFunc); err != nil {
		return err
	}
	s.setupAnnouncementReceiver(ctx, cancelFunc)
	return nil
}