package ext import ( "errors" "fmt" "log/slog" "net/http" "git.gabrielgio.me/cerrado/pkg/service" "git.gabrielgio.me/cerrado/templates" ) type ( Router struct { middlewares []Middleware router *http.ServeMux } Middleware func(next http.HandlerFunc) http.HandlerFunc ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error ) func NewRouter() *Router { return &Router{ router: http.NewServeMux(), } } func (r *Router) Handler() http.Handler { return r.router } func (r *Router) AddMiddleware(middleware Middleware) { r.middlewares = append(r.middlewares, middleware) } func wrapError(next ErrorRequestHandler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := next(w, r); err != nil { if errors.Is(err, service.ErrRepositoryNotFound) { NotFound(w, r) } else { slog.Error("Internal Server Error", "error", err) InternalServerError(r, w, err) } } } } func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc { return func(w http.ResponseWriter, re *http.Request) { req := wrapError(next) for _, r := range r.middlewares { req = r(req) } req(w, re) } } func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) { r.router.HandleFunc(path, r.run(handler)) } func NotFound(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) templates.WritePageTemplate(w, &templates.ErrorPage{ Message: "Not Found", }, r.Context()) } func Redirect(w http.ResponseWriter, location string) { w.Header().Add("location", location) w.WriteHeader(http.StatusTemporaryRedirect) } func InternalServerError(r *http.Request, w http.ResponseWriter, err error) { w.WriteHeader(http.StatusInternalServerError) templates.WritePageTemplate(w, &templates.ErrorPage{ Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()), }, r.Context()) }