1package ext
2
3import (
4 "errors"
5 "fmt"
6 "log/slog"
7 "net/http"
8
9 "git.gabrielgio.me/cerrado/pkg/service"
10 "git.gabrielgio.me/cerrado/templates"
11)
12
13type (
14 Router struct {
15 middlewares []Middleware
16 router *http.ServeMux
17 }
18 Middleware func(next http.HandlerFunc) http.HandlerFunc
19 ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error
20)
21
22func NewRouter() *Router {
23 return &Router{
24 router: http.NewServeMux(),
25 }
26}
27
28func (r *Router) Handler() http.Handler {
29 return r.router
30}
31
32func (r *Router) AddMiddleware(middleware Middleware) {
33 r.middlewares = append(r.middlewares, middleware)
34}
35
36func wrapError(next ErrorRequestHandler) http.HandlerFunc {
37 return func(w http.ResponseWriter, r *http.Request) {
38 if err := next(w, r); err != nil {
39 if errors.Is(err, service.ErrRepositoryNotFound) {
40 NotFound(w, r)
41 } else {
42 slog.Error("Internal Server Error", "error", err)
43 InternalServerError(r, w, err)
44 }
45 }
46 }
47}
48
49func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc {
50 return func(w http.ResponseWriter, re *http.Request) {
51 req := wrapError(next)
52 for _, r := range r.middlewares {
53 req = r(req)
54 }
55 req(w, re)
56 }
57}
58
59func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) {
60 r.router.HandleFunc(path, r.run(handler))
61}
62
63func NotFound(w http.ResponseWriter, r *http.Request) {
64 w.WriteHeader(http.StatusNotFound)
65 templates.WritePageTemplate(w, &templates.ErrorPage{
66 Message: "Not Found",
67 }, r.Context())
68}
69
70func Redirect(w http.ResponseWriter, location string) {
71 w.Header().Add("location", location)
72 w.WriteHeader(http.StatusTemporaryRedirect)
73}
74
75func InternalServerError(r *http.Request, w http.ResponseWriter, err error) {
76 w.WriteHeader(http.StatusInternalServerError)
77 templates.WritePageTemplate(w, &templates.ErrorPage{
78 Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
79 }, r.Context())
80}