func middlewareHandler(nextFunction httprouter.Handle) httprouter.Handle {
	return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		dumpedRequest := dumpRequest(request)
		responseRecorder := httptest.NewRecorder()
		nextFunction(responseRecorder, request, params)
		if responseRecorder.Code == http.StatusInternalServerError {
			log.Printf("Request %s", dumpedRequest)
			log.Printf("Response %s", dumpResponse(responseRecorder))
		}
		for key, value := range responseRecorder.HeaderMap {
			writer.Header()[key] = value
		}
		writer.WriteHeader(responseRecorder.Code)
		responseRecorder.Body.WriteTo(writer)
	}
}
/*
middlewareHandler is a wrapper to catch all client requests
package main
import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
	pip "github.com/JamesMilnerUK/pip-go"
	"github.com/julienschmidt/httprouter"
	"github.com/printmaps/printmaps/pd"
	"github.com/rs/cors"
	yaml "gopkg.in/yaml.v2"
)
type Config struct {
	Logfile         string
	Workdir         string
	Addr            string
	Capafile        string
	Polyfile        string
	Maintenancefile string
	Maintenancemode bool
}
var config Config
var (
	progName    = os.Args[0]
	progVersion = "v0.8.0"
	progDate    = "2021/06/12"
	progPurpose = "Printmaps Webservice"
	progInfo    = "Webservice to build large printable maps based on OSM data."
)
var (
	pPolygon            pip.Polygon
	pPolygonBoundingBox pip.BoundingBox
)
type ConfigMapformat struct {
	Type           string
	MinPrintWidth  float64
	MaxPrintWidth  float64
	MinPrintHeigth float64
	MaxPrintHeigth float64
}
type ConfigMapscale struct {
	MinScale int
	MaxScale int
}
type ConfigMapdata struct {
	Description  string
	MinLatitude  float64
	MaxLatitude  float64
	MinLongitude float64
	MaxLongitude float64
}
type ConfigStyle struct {
	Name             string
	ShortDescription string
	LongDescription  string
	Release          string
	Date             string
	Link             string
	Copyright        string
	Layers           string
}
type PrintmapsFeature struct {
	ConfigMapdata    ConfigMapdata
	ConfigMapformats []ConfigMapformat
	ConfigMapscale   ConfigMapscale
	ConfigStyles     []ConfigStyle
}
var (
	pmFeature PrintmapsFeature  
)
func init() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
}
func main() {
	configfile := "printmaps_webservice.yaml"
	if len(os.Args) > 1 {
		configfile = os.Args[1]
	}
	source, err := ioutil.ReadFile(configfile)
	if err != nil {
		log.Fatalf("fatal error <%v> at ioutil.ReadFile(), file = <%s>", err, configfile)
	}
	if err = yaml.Unmarshal(source, &config); err != nil {
		log.Fatalf("fatal error <%v> at yaml.Unmarshal()", err)
	}
	logfile, err := os.OpenFile(config.Logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalf("fatal error <%v> at os.OpenFile(), file = <%v>", err, config.Logfile)
	}
	defer logfile.Close()
	log.SetOutput(logfile)
	fmt.Printf("%s (%s) startet. See '%s' for further details.\n", progName, progPurpose, config.Logfile)
	log.Printf("name = %s", progName)
	log.Printf("release = %s - %s", progVersion, progDate)
	log.Printf("purpose = %s", progPurpose)
	log.Printf("info = %s", progInfo)
	log.Printf("config addr = %s", config.Addr)
	log.Printf("config capafile  = %s", config.Capafile)
	log.Printf("config polyfile = %s", config.Polyfile)
	log.Printf("config logfile = %s", config.Logfile)
	log.Printf("config maintenancefile = %s", config.Maintenancefile)
	log.Printf("config maintenancemode = %t", config.Maintenancemode)
	if err = os.Chdir(config.Workdir); err != nil {
		log.Fatalf("fatal error <%v> at os.Chdir(), dir = <%s>", err, config.Workdir)
	}
	pd.PathWorkdir, err = os.Getwd()
	if err != nil {
		log.Fatalf("fatal error <%v> at os.Getwd()", err)
	}
	log.Printf("config workdir (relative) = %s", config.Workdir)
	log.Printf("workdir (absolute) = %s", pd.PathWorkdir)
	pid := os.Getpid()
	log.Printf("own process identifier (pid) = %d", pid)
	log.Printf("shutdown with SIGINT or SIGTERM")
	pd.CreateDirectories()
	if config.Polyfile != "" {
		if err := readPolyfile(config.Polyfile, &pPolygon); err != nil {
			log.Fatalf("fatal error <%v> at readPolyfile(), file = <%v>", err, config.Polyfile)
		}
		pPolygonBoundingBox = pip.GetBoundingBox(pPolygon)
	}
	if err := readCapafile(config.Capafile, &pmFeature); err != nil {
		log.Fatalf("fatal error <%v> at readCapafile(), file = <%v>", err, config.Capafile)
	}
	if config.Polyfile != "" {
		pmFeature.ConfigMapdata.MinLatitude = pPolygonBoundingBox.BottomLeft.Y
		pmFeature.ConfigMapdata.MaxLatitude = pPolygonBoundingBox.TopRight.Y
		pmFeature.ConfigMapdata.MinLongitude = pPolygonBoundingBox.BottomLeft.X
		pmFeature.ConfigMapdata.MaxLongitude = pPolygonBoundingBox.TopRight.X
	}
	log.Printf("MinLatitude = %f", pmFeature.ConfigMapdata.MinLatitude)
	log.Printf("MaxLatitude = %f", pmFeature.ConfigMapdata.MaxLatitude)
	log.Printf("MinLongitude = %f", pmFeature.ConfigMapdata.MinLongitude)
	log.Printf("MaxLongitude = %f", pmFeature.ConfigMapdata.MaxLongitude)
	router := httprouter.New()
	if config.Maintenancemode == false {
		router.GET("/api/beta2/maps/metadata/:id", middlewareHandler(fetchMetadata))
		router.GET("/api/beta2/maps/mapstate/:id", middlewareHandler(fetchMapstate))
		router.GET("/api/beta2/maps/mapfile/:id", middlewareHandler(fetchMapfile))
		router.POST("/api/beta2/maps/metadata", middlewareHandler(createMetadata))
		router.POST("/api/beta2/maps/mapfile", middlewareHandler(createMapfile))
		router.PATCH("/api/beta2/maps/metadata", middlewareHandler(updateMetadata))
		router.POST("/api/beta2/maps/metadata/patch", middlewareHandler(updateMetadata))  
		router.DELETE("/api/beta2/maps/:id", middlewareHandler(deleteMap))
		router.POST("/api/beta2/maps/delete/:id", middlewareHandler(deleteMap))  
		router.GET("/api/beta2/maps/capabilities/service", middlewareHandler(revealCapaService))
		router.GET("/api/beta2/maps/capabilities/mapdata", middlewareHandler(revealCapaMapdata))
		router.POST("/api/beta2/maps/upload/:id", middlewareHandler(uploadUserdata))
	} else {
		log.Printf("--> MAINTENANCE MODE ACTIVATED <--")
		log.Printf("--> service responses to each request with '503 Service Unavailable' and the maintenance file <--")
		router.GET("/*name", showMaintenance)
	}
	stopChan := make(chan os.Signal)
	signal.Notify(stopChan, syscall.SIGINT)   
	signal.Notify(stopChan, syscall.SIGTERM)  
	pmWebservice := &http.Server{Addr: config.Addr, Handler: cors.Default().Handler(router)}
	go func() {
		log.Printf("Listen for requests on port %s ...", config.Addr)
		if err := pmWebservice.ListenAndServe(); err != nil {
			log.Fatalf("fatal error <%v> at pmWebservice.ListenAndServe()", err)
		}
	}()
	sig := <-stopChan
	log.Printf("Signal <%v> received, shutting down %s (%s) ...", sig, progName, progPurpose)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := pmWebservice.Shutdown(ctx); err != nil {
		log.Fatalf("fatal error <%v> at pmWebservice.Shutdown()", err)
	}
	log.Printf("%s (%s) gracefully shut down.", progName, progPurpose)
}