package api import ( "bytes" "encoding/json" "math/rand" "net/http" "time" "github.com/stefanprodan/podinfo/pkg/version" "go.uber.org/zap" ) func randomDelayMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { min := 0 max := 5 rand.Seed(time.Now().Unix()) delay := rand.Intn(max-min) + min time.Sleep(time.Duration(delay) * time.Second) next.ServeHTTP(w, r) }) } func randomErrorMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rand.Seed(time.Now().Unix()) if rand.Int31n(3) == 0 { errors := []int{http.StatusInternalServerError, http.StatusBadRequest, http.StatusConflict} w.WriteHeader(errors[rand.Intn(len(errors))]) return } next.ServeHTTP(w, r) }) } func versionMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Header.Set("X-API-Version", version.VERSION) r.Header.Set("X-API-Revision", version.REVISION) next.ServeHTTP(w, r) }) } // TODO: use Istio tracing package // https://github.com/istio/istio/blob/master/pkg/tracing/config.go func copyTracingHeaders(from *http.Request, to *http.Request) { headers := []string{ "x-request-id", "x-b3-traceid", "x-b3-spanid", "x-b3-parentspanid", "x-b3-sampled", "x-b3-flags", "x-ot-span-context", } for i := range headers { headerValue := from.Header.Get(headers[i]) if len(headerValue) > 0 { to.Header.Set(headers[i], headerValue) } } } func (s *Server) JSONResponse(w http.ResponseWriter, r *http.Request, result interface{}) { body, err := json.Marshal(result) if err != nil { w.WriteHeader(http.StatusInternalServerError) s.logger.Error("JSON marshal failed", zap.Error(err)) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(http.StatusOK) w.Write(prettyJSON(body)) } func (s *Server) JSONResponseCode(w http.ResponseWriter, r *http.Request, result interface{}, responseCode int) { body, err := json.Marshal(result) if err != nil { w.WriteHeader(http.StatusInternalServerError) s.logger.Error("JSON marshal failed", zap.Error(err)) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(responseCode) w.Write(prettyJSON(body)) } func (s *Server) ErrorResponse(w http.ResponseWriter, r *http.Request, error string, code int) { data := struct { Code int `json:"code"` Message string `json:"message"` }{ Code: code, Message: error, } body, err := json.Marshal(data) if err != nil { w.WriteHeader(http.StatusInternalServerError) s.logger.Error("JSON marshal failed", zap.Error(err)) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(http.StatusOK) w.Write(prettyJSON(body)) } func prettyJSON(b []byte) []byte { var out bytes.Buffer json.Indent(&out, b, "", " ") return out.Bytes() }