package handlers import ( "io/fs" "net/http" "time" "git.vbrandl.net/vbrandl/go-web-template/service" "github.com/gorilla/mux" "github.com/justinas/alice" "github.com/rs/zerolog/hlog" "github.com/rs/zerolog/log" ) type Application struct { Service *service.Service StaticFiles fs.FS } func NewApplication(service *service.Service, staticFiles fs.FS) (Application, error) { application := Application{ Service: service, StaticFiles: staticFiles, } err := application.ParseTemplates() return application, err } func (app *Application) Routes() *mux.Router { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", app.Index).Methods("GET") router.HandleFunc("/health", app.HealthCheck).Methods("GET") // strip off the location such that we route correctly staticContent, err := fs.Sub(app.StaticFiles, "static") if err != nil { log.Fatal().Err(err).Msg("error with static content") } f := http.FileServerFS(staticContent) router.PathPrefix("/static/").Handler(http.StripPrefix("/static", f)) router.NotFoundHandler = http.HandlerFunc(app.NotFound) return router } func (app *Application) Handler() http.Handler { logger := log.Logger middlewares := alice.New(). Append(hlog.NewHandler(logger)). Append(hlog.AccessHandler(func(r *http.Request, status int, size int, duration time.Duration) { hlog.FromRequest(r).Info(). Str("method", r.Method). Stringer("url", r.URL). Int("status", status). Int("size", size). Str("remote-addr", r.RemoteAddr). Dur("duration", duration). Str("user-agent", r.UserAgent()). Msg("") })). Append(hlog.RequestIDHandler("request-id", "x-request-id")) routes := app.Routes() return middlewares.Then(routes) } func RequestID(r *http.Request) string { if id, ok := hlog.IDFromRequest(r); ok { return id.String() } else { l := hlog.FromRequest(r) l.Warn().Msg("No associated request ID") return "unknown" } }