func (ed *EndpointsServer) transformJsonrpcResponse(spiRequest *apiRequest, responseBody string) (string, error) {
	var result interface{}
	err := json.Unmarshal([]byte(responseBody), &result)
	if err != nil {
		return responseBody, fmt.Errorf("Problem unmarshalling RPC response: %s", err.Error())
	}
	bodyJson := map[string]interface{}{"result": result}
	return ed.finishRpcResponse(spiRequest.requestId, spiRequest.isBatch, bodyJson), nil
}
Translates an api-serving response to a JsonRpc response.

Returns the updated, JsonRPC-formatted request body.
package server
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/rwl/go-endpoints/endpoints"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"
)
const defaultURL = "http://localhost:8080"
const defaultRoot = "/_ah/api/"
const spiRootFormat = "/_ah/spi/%s"
var apiExplorerUrl = "http://apis-explorer.appspot.com/apis-explorer/?base="
type EndpointsServer struct {
	configManager *apiConfigManager
	root string
	url string
}
func NewEndpointsServer(URL *url.URL) *EndpointsServer {
	return newEndpointsServerConfig(newApiConfigManager(), "", URL)
}
func NewEndpointsServerRoot(root string, URL *url.URL) *EndpointsServer {
	return newEndpointsServerConfig(newApiConfigManager(), root, URL)
}
func newEndpointsServer() *EndpointsServer {
	u, _ := url.Parse(defaultURL)
	return newEndpointsServerConfig(newApiConfigManager(), "", u)
}
func newEndpointsServerConfig(configManager *apiConfigManager, root string, u *url.URL) *EndpointsServer {
	if root == "" {
		root = defaultRoot
	}
	s := &EndpointsServer{configManager: configManager, root: root}
	s.SetURL(u)
	return s
}
func (ed *EndpointsServer) HandleHttp(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	r := newRouter()
	r.HandleFunc(path.Join(ed.root, "/explorer"), ed.HandleApiExplorerRequest)
	r.HandleFunc(path.Join(ed.root, "/static"), ed.HandleApiStaticRequest)
	r.HandleFunc("/", ed.ServeHTTP)
	mux.Handle(ed.root, r)
}
func (ed *EndpointsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ar, err := newApiRequest(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	ed.serveHTTP(w, ar)
}
func (ed *EndpointsServer) serveHTTP(w http.ResponseWriter, ar *apiRequest) {
	apiConfigResponse, err := ed.getApiConfigs()
	if err != nil {
		ed.failRequest(w, ar.Request, "BackendService.getApiConfigs error: "+err.Error())
		return
	}
	err = ed.handleApiConfigResponse(apiConfigResponse)
	if err != nil {
		ed.failRequest(w, ar.Request, "BackendService.getApiConfigs handling error: "+err.Error())
		return
	}
	_, err = callSpi(ed, w, ar)
	if err != nil {
		reqErr, ok := err.(requestError)
		if ok {
			ed.handleRequestError(w, ar, reqErr)
			return
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}
func (ed *EndpointsServer) HandleApiExplorerRequest(w http.ResponseWriter, r *http.Request) {
	b := url.URL{Scheme: "http", Host: r.URL.Host, Path: ed.root}
	baseUrl := b.String()
	redirectUrl := apiExplorerUrl + baseUrl
	sendRedirectResponse(redirectUrl, w, r, nil)
}
func (ed *EndpointsServer) HandleApiStaticRequest(w http.ResponseWriter, r *http.Request) {
	request, err := newApiRequest(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	response, body, err := getStaticFile(request.relativeUrl)
	if err == nil && response.StatusCode == 200 {
		w.Header().Add("Content-Type", response.Header.Get("Content-Type"))
		w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body)))
		fmt.Fprintf(w, body)
	} else {
		log.Printf("Discovery API proxy failed on %s with %d. Details: %s",
			request.relativeUrl, response.StatusCode, body)
		w.Header().Add("Content-Type", response.Header.Get("Content-Type"))
		w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body)))
		w.WriteHeader(response.StatusCode)
		fmt.Fprint(w, body)
		return
	}
}
func (ed *EndpointsServer) getApiConfigs() (*http.Response, error) {
	req, err := http.NewRequest("POST",
		ed.url+"/_ah/spi/BackendService.getApiConfigs",
		ioutil.NopCloser(bytes.NewBufferString("{}")))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}
func verifyResponse(response *http.Response, statusCode int, contentType string) error {
	if response.StatusCode != statusCode {
		return fmt.Errorf("HTTP status code does not match the response status code: %d != %d", statusCode, response.StatusCode)
	}
	if len(contentType) == 0 {
		return nil
	}
	ct := response.Header.Get("Content-Type")
	if len(ct) == 0 {
		return errors.New("Response does not specify a Content-Type")
	}
	if ct == contentType {
		return nil
	}
	return fmt.Errorf("Incorrect response Content-Type: %s != %s", ct, contentType)
}
func (ed *EndpointsServer) handleApiConfigResponse(apiConfigResponse *http.Response) error {
	err := verifyResponse(apiConfigResponse, 200, "application/json")
	if err == nil {
		body, err := ioutil.ReadAll(apiConfigResponse.Body)
		defer apiConfigResponse.Body.Close()
		if err != nil {
			return err
		}
		err = ed.configManager.parseApiConfigResponse(string(body))
		if err != nil {
			return err
		}
		return nil
	}
	return err
}
var callSpi = func(ed *EndpointsServer, w http.ResponseWriter, origRequest *apiRequest) (string, error) {
	var methodConfig *endpoints.ApiMethod
	var params map[string]string
	if origRequest.isRpc() {
		methodConfig = ed.lookupRpcMethod(origRequest)
		params = nil
	} else {
		methodConfig, params = ed.lookupRestMethod(origRequest)
	}
	if methodConfig == nil {
		corsHandler := newCheckCorsHeaders(origRequest.Request)
		return sendNotFoundResponse(w, corsHandler), nil
	}
	spiRequest, err := ed.transformRequest(origRequest, params, methodConfig)
	if err != nil {
		return err.Error(), err
	}
	discovery := newDiscoveryService(ed.configManager)
	discoveryResponse, ok := discovery.handleDiscoveryRequest(spiRequest.URL.Path,
		spiRequest, w)
	if ok {
		return discoveryResponse, nil
	}
	url := buildSpiUrl(ed, spiRequest)
	req, err := http.NewRequest("POST", url, spiRequest.Body)
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/json")
	req.RemoteAddr = spiRequest.RemoteAddr
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	return handleSpiResponse(ed, origRequest, spiRequest, resp,
		methodConfig, w)
}
var buildSpiUrl = func(ed *EndpointsServer, spiRequest *apiRequest) string {
	return ed.url + fmt.Sprintf(spiRootFormat, spiRequest.URL.Path)
}
var handleSpiResponse = func(ed *EndpointsServer, origRequest, spiRequest *apiRequest, response *http.Response, methodConfig *endpoints.ApiMethod, w http.ResponseWriter) (string, error) {
	for header, value := range response.Header {
		if header == "Content-Type" && !strings.HasPrefix(value[0], "application/json") {
			respBody, err := ioutil.ReadAll(response.Body)
			if err != nil {
				return "", err
			}
			response.Body.Close()
			return ed.failRequest(w, origRequest.Request,
				fmt.Sprintf("Non-JSON reply: %s", respBody)), nil
		}
	}
	err := ed.checkErrorResponse(response)
	if err != nil {
		return "", err
	}
	respBody, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	response.Body.Close()
	var body string
	if origRequest.isRpc() {
		body, err = ed.transformJsonrpcResponse(spiRequest, string(respBody))
	} else {
		emptyResponse := ed.checkEmptyResponse(origRequest, methodConfig, w)
		if emptyResponse {
			return "", nil
		}
		body, err = ed.transformRestResponse(string(respBody))
	}
	if err != nil {
		return body, err
	}
	corsHandler := newCheckCorsHeaders(origRequest.Request)
	corsHandler.updateHeaders(w.Header())
	for k, vals := range response.Header {
		w.Header()[k] = vals
	}
	w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body)))
	w.WriteHeader(response.StatusCode)
	fmt.Fprint(w, body)
	return body, nil
}
func (ed *EndpointsServer) failRequest(w http.ResponseWriter, origRequest *http.Request, message string) string {
	corsHandler := newCheckCorsHeaders(origRequest)
	return sendErrorResponse(message, w, corsHandler)
}
func (ed *EndpointsServer) lookupRestMethod(origRequest *apiRequest) (*endpoints.ApiMethod, map[string]string) {
	methodName, method, params := ed.configManager.lookupRestMethod(origRequest.URL.Path, origRequest.Method)
	origRequest.Method = methodName
	return method, params
}
func (ed *EndpointsServer) lookupRpcMethod(origRequest *apiRequest) *endpoints.ApiMethod {
	if origRequest.bodyJson == nil {
		return nil
	}
	methodName, ok := origRequest.bodyJson["method"]
	methodNameStr, ok2 := methodName.(string)
	if !ok || !ok2 {
		methodNameStr = ""
	}
	version, ok := origRequest.bodyJson["apiVersion"]
	versionStr, ok3 := version.(string)
	if !ok || !ok3 {
		versionStr = ""
	}
	origRequest.Method = methodNameStr
	return ed.configManager.lookupRpcMethod(methodNameStr, versionStr)
}
func (ed *EndpointsServer) transformRequest(origRequest *apiRequest, params map[string]string, methodConfig *endpoints.ApiMethod) (*apiRequest, error) {
	var request *apiRequest
	var err error
	if origRequest.isRpc() {
		request, err = ed.transformJsonrpcRequest(origRequest)
	} else {
		methodParams := methodConfig.Request.Params
		request, err = ed.transformRestRequest(origRequest, params, methodParams)
	}
	if err != nil {
		return request, err
	}
	request.URL.Path = methodConfig.RosyMethod
	return request, nil
}
func (ed *EndpointsServer) addMessageField(fieldName string, value interface{}, params map[string]interface{}) {
	pos := strings.Index(fieldName, ".")
	if pos == -1 {
		params[fieldName] = value
		return
	}
	substr := strings.SplitN(fieldName, ".", 2)
	root, remaining := substr[0], substr[1]
	var subParams map[string]interface{}
	_subParams, ok := params[root]
	if ok {
		subParams, ok = _subParams.(map[string]interface{})
		if !ok {
			log.Printf("Problem accessing sub-params: %#v", _subParams)
		}
	} else {
		subParams = make(map[string]interface{})
		params[root] = subParams
	}
	ed.addMessageField(remaining, value, subParams)
}
func (ed *EndpointsServer) updateFromBody(destination map[string]interface{}, source map[string]interface{}) {
	for key, value := range source {
		destinationValue, ok := destination[key]
		if ok {
			val, okVal := value.(map[string]interface{})
			destValue, okDest := destinationValue.(map[string]interface{})
			if okVal && okDest {
				ed.updateFromBody(destValue, val)
			} else {
				destination[key] = value
			}
		} else {
			destination[key] = value
		}
	}
}
func (ed *EndpointsServer) transformRestRequest(origRequest *apiRequest,
	params map[string]string,
	methodParameters map[string]*endpoints.ApiRequestParamSpec) (*apiRequest, error) {
	request, err := origRequest.copy()
	if err != nil {
		return request, err
	}
	bodyJson := make(map[string]interface{})
	for key, value := range params {
		bodyJson[key] = []string{value}
	}
	if len(request.URL.RawQuery) > 0 {
		for key, value := range request.URL.Query() {
			if jsonVal, ok := bodyJson[key]; ok {
				jsonArr, ok := jsonVal.([]string)
				if ok {
					bodyJson[key] = append(value, jsonArr...)
				} else {
					panic(fmt.Sprintf("String array expected: %#v", jsonVal))
				}
			} else {
				bodyJson[key] = value
			}
		}
	}
	for key, _ := range bodyJson {
		currentParameter, ok := methodParameters[key]
		if !ok {
			currentParameter = &endpoints.ApiRequestParamSpec{}
		}
		repeated := false
		if ok {
			repeated = currentParameter.Repeated
		}
		if !repeated {
			val := bodyJson[key]
			valArr, ok := val.([]string)
			if ok {
				if len(valArr) > 0 {
					bodyJson[key] = valArr[0]
				} else {
					bodyJson[key] = ""  
				}
			} else {
				panic(fmt.Sprintf("String array expected: %#v", val))
			}
		}
		bodyJson[key], err = transformParameterValue(key, bodyJson[key],
			currentParameter)
		if err != nil {
			return request, err
		}
		messageValue := bodyJson[key]
		delete(bodyJson, key)
		ed.addMessageField(key, messageValue, bodyJson)
	}
	if request.bodyJson != nil {
		ed.updateFromBody(bodyJson, request.bodyJson)
	}
	body, err := json.Marshal(bodyJson)
	if err == nil {
		request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	} else {
		return request, err
	}
	json.Unmarshal(body, &request.bodyJson)  
	return request, nil
}
func (ed *EndpointsServer) transformJsonrpcRequest(origRequest *apiRequest) (*apiRequest, error) {
	request, err := origRequest.copy()
	if err != nil {
		return request, err
	}
	requestId, okId := request.bodyJson["id"]
	if okId {
		requestIdStr, ok := requestId.(string)
		if ok {
			request.requestId = requestIdStr
		} else {
			requestIdInt, ok := requestId.(int)
			if ok {
				request.requestId = fmt.Sprintf("%d", requestIdInt)
			} else {
				return nil, fmt.Errorf("Problem extracting request ID: %#v", requestId)
			}
		}
	} else {
		request.requestId = ""
	}
	bodyJson, okParam := request.bodyJson["params"]
	if okParam {
		bodyJsonObj, ok := bodyJson.(map[string]interface{})
		if ok {
			request.bodyJson = bodyJsonObj
		} else {
			bodyJsonMap, ok := bodyJson.(map[string]interface{})
			if ok {
				request.bodyJson = bodyJsonMap
			} else {
				return nil, fmt.Errorf("Problem extracting JSON body from params: %#v", bodyJson)
			}
		}
	} else {
		request.bodyJson = make(map[string]interface{})
	}
	body, err := json.Marshal(request.bodyJson)
	if err != nil {
		return request, fmt.Errorf("Problem transforming RPC request: %s", err.Error())
	}
	request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	return request, nil
}
func (ed *EndpointsServer) checkErrorResponse(response *http.Response) error {
	if response.StatusCode >= 300 {
		return newBackendError(response)
	}
	return nil
}
func (ed *EndpointsServer) checkEmptyResponse(origRequest *apiRequest, methodConfig *endpoints.ApiMethod, w http.ResponseWriter) bool {
	if methodConfig.Response.Body == "empty" {
		corsHandler := newCheckCorsHeaders(origRequest.Request)
		sendNoContentResponse(w, corsHandler)
		return true
	}
	return false
}
func (ed *EndpointsServer) transformRestResponse(responseBody string) (string, error) {
	var bodyJson map[string]interface{}
	err := json.Unmarshal([]byte(responseBody), &bodyJson)
	if err != nil {
		return responseBody, fmt.Errorf("Problem transforming REST response: %s", err.Error())
	}
	body, _ := json.MarshalIndent(bodyJson, "", "  ")  
	return string(body), nil
}