func GetBasketResponse(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if _, basket := getAuthenticatedBasket(w, r, ps); basket != nil {
		method, errm := getValidMethod(ps)
		if errm != nil {
			http.Error(w, errm.Error(), http.StatusBadRequest)
		} else {
			response := basket.GetResponse(method)
			if response == nil {
				response = &defaultResponse
			}
			json, err := json.Marshal(response)
			writeJSON(w, http.StatusOK, json, err)
		}
	}
}
GetBasketResponse handles HTTP request to get basket response configuration
package main
import (
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"github.com/julienschmidt/httprouter"
)
var validBasketName = regexp.MustCompile(basketNamePattern)
var defaultResponse = ResponseConfig{Status: http.StatusOK, Headers: http.Header{}, IsTemplate: false}
var indexPageTemplate = template.Must(template.New("index").Parse(indexPageContentTemplate))
var basketPageTemplate = template.Must(template.New("basket").Parse(basketPageContentTemplate))
var basketsPageTemplate = template.Must(template.New("baskets").Parse(basketsPageContentTemplate))
func writeJSON(w http.ResponseWriter, status int, json []byte, err error) {
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(status)
		w.Write(json)
	}
}
func parseInt(value string, min int, max int, defaultValue int) int {
	if len(value) > 0 {
		if i, err := strconv.Atoi(value); err == nil {
			switch {
			case i < min:
				return min
			case i > max:
				return max
			default:
				return i
			}
		}
	}
	return defaultValue
}
func getPage(values url.Values) (int, int) {
	max := parseInt(values.Get("max"), 1, serverConfig.PageSize*10, serverConfig.PageSize)
	skip := parseInt(values.Get("skip"), 0, serverConfig.MaxCapacity, 0)
	return max, skip
}
func getAuthenticatedBasket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) (string, Basket) {
	name := ps.ByName("basket")
	if !validBasketName.MatchString(name) {
		http.Error(w, "invalid basket name; the name does not match pattern: "+validBasketName.String(), http.StatusBadRequest)
	} else if basket := basketsDb.Get(name); basket != nil {
		if token := r.Header.Get("Authorization"); basket.Authorize(token) || token == serverConfig.MasterToken {
			return name, basket
		}
		w.WriteHeader(http.StatusUnauthorized)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
	return "", nil
}
func validateBasketConfig(config *BasketConfig) error {
	if config.Capacity < 1 {
		return fmt.Errorf("capacity should be a positive number, but was %d", config.Capacity)
	}
	if config.Capacity > serverConfig.MaxCapacity {
		return fmt.Errorf("capacity may not be greater than %d", serverConfig.MaxCapacity)
	}
	if len(config.ForwardURL) > 0 {
		if _, err := url.ParseRequestURI(config.ForwardURL); err != nil {
			return err
		}
	}
	return nil
}
func validateResponseConfig(config *ResponseConfig) error {
	if config.Status < 100 || config.Status >= 600 {
		return fmt.Errorf("invalid HTTP status of response: %d", config.Status)
	}
	if config.IsTemplate && len(config.Body) > 0 {
		if _, err := template.New("body").Parse(config.Body); err != nil {
			return fmt.Errorf("error in body %s", err)
		}
	}
	return nil
}
func getValidMethod(ps httprouter.Params) (string, error) {
	method := strings.ToUpper(ps.ByName("method"))
	switch method {
	case http.MethodGet,
		http.MethodHead,
		http.MethodPost,
		http.MethodPut,
		http.MethodPatch,
		http.MethodDelete,
		http.MethodConnect,
		http.MethodOptions,
		http.MethodTrace:
		return method, nil
	}
	return method, fmt.Errorf("unknown HTTP method: %s", method)
}
func GetBaskets(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if r.Header.Get("Authorization") != serverConfig.MasterToken {
		w.WriteHeader(http.StatusUnauthorized)
	} else {
		values := r.URL.Query()
		if query := values.Get("q"); len(query) > 0 {
			max, skip := getPage(values)
			json, err := json.Marshal(basketsDb.FindNames(query, max, skip))
			writeJSON(w, http.StatusOK, json, err)
		} else {
			json, err := json.Marshal(basketsDb.GetNames(getPage(values)))
			writeJSON(w, http.StatusOK, json, err)
		}
	}
}
func GetStats(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if r.Header.Get("Authorization") != serverConfig.MasterToken {
		w.WriteHeader(http.StatusUnauthorized)
	} else {
		max := parseInt(r.URL.Query().Get("max"), 1, 100, 5)
		json, err := json.Marshal(basketsDb.GetStats(max))
		writeJSON(w, http.StatusOK, json, err)
	}
}
func GetVersion(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	json, err := json.Marshal(version)
	writeJSON(w, http.StatusOK, json, err)
}
func GetBasket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if _, basket := getAuthenticatedBasket(w, r, ps); basket != nil {
		json, err := json.Marshal(basket.Config())
		writeJSON(w, http.StatusOK, json, err)
	}
}
func CreateBasket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	name := ps.ByName("basket")
	if name == serviceOldAPIPath || name == serviceAPIPath || name == serviceUIPath {
		http.Error(w, "This basket name conflicts with reserved system path: "+name, http.StatusForbidden)
		return
	}
	if !validBasketName.MatchString(name) {
		http.Error(w, "invalid basket name; the name does not match pattern: "+validBasketName.String(), http.StatusBadRequest)
		return
	}
	log.Printf("[info] creating basket: %s", name)
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 2048))
	r.Body.Close()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	config := BasketConfig{ForwardURL: "", Capacity: serverConfig.InitCapacity}
	if len(body) > 0 {
		if err = json.Unmarshal(body, &config); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if err = validateBasketConfig(&config); err != nil {
			http.Error(w, err.Error(), http.StatusUnprocessableEntity)
			return
		}
	}
	auth, err := basketsDb.Create(name, config)
	if err != nil {
		http.Error(w, err.Error(), http.StatusConflict)
	} else {
		json, err := json.Marshal(auth)
		writeJSON(w, http.StatusCreated, json, err)
	}
}
func UpdateBasket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if _, basket := getAuthenticatedBasket(w, r, ps); basket != nil {
		body, err := ioutil.ReadAll(io.LimitReader(r.Body, 2048))
		r.Body.Close()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		} else if len(body) > 0 {
			config := basket.Config()
			if err = json.Unmarshal(body, &config); err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			if err = validateBasketConfig(&config); err != nil {
				http.Error(w, err.Error(), http.StatusUnprocessableEntity)
				return
			}
			basket.Update(config)
			w.WriteHeader(http.StatusNoContent)
		} else {
			w.WriteHeader(http.StatusNotModified)
		}
	}
}
func DeleteBasket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if name, basket := getAuthenticatedBasket(w, r, ps); basket != nil {
		log.Printf("[info] deleting basket: %s", name)
		basketsDb.Delete(name)
		w.WriteHeader(http.StatusNoContent)
	}
}