aboutsummaryrefslogtreecommitdiff
path: root/pkg/ext
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/ext')
-rw-r--r--pkg/ext/compression.go2
-rw-r--r--pkg/ext/log.go53
-rw-r--r--pkg/ext/router.go72
3 files changed, 126 insertions, 1 deletions
diff --git a/pkg/ext/compression.go b/pkg/ext/compression.go
index 92144b8..57ad49a 100644
--- a/pkg/ext/compression.go
+++ b/pkg/ext/compression.go
@@ -24,7 +24,7 @@ type CompressionResponseWriter struct {
compressWriter io.Writer
}
-func Compress(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
+func Compress(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if accept, ok := r.Header["Accept-Encoding"]; ok {
if compress, algo := GetCompressionWriter(u.FirstOrZero(accept), w); algo != "" {
diff --git a/pkg/ext/log.go b/pkg/ext/log.go
new file mode 100644
index 0000000..a9d26a9
--- /dev/null
+++ b/pkg/ext/log.go
@@ -0,0 +1,53 @@
+package ext
+
+import (
+ "log/slog"
+ "net/http"
+ "time"
+)
+
+type statusWraper struct {
+ statusCode int
+ innerWriter http.ResponseWriter
+}
+
+func (s *statusWraper) Header() http.Header {
+ return s.innerWriter.Header()
+}
+
+func (s *statusWraper) Write(b []byte) (int, error) {
+ return s.innerWriter.Write(b)
+}
+
+func (s *statusWraper) WriteHeader(statusCode int) {
+ s.statusCode = statusCode
+ s.innerWriter.WriteHeader(statusCode)
+}
+
+func (s *statusWraper) StatusCode() int {
+ if s.statusCode == 0 {
+ return 200
+ }
+ return s.statusCode
+}
+
+func wrap(w http.ResponseWriter) *statusWraper {
+ return &statusWraper{
+ innerWriter: w,
+ }
+}
+
+func Log(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ t := time.Now()
+ s := wrap(w)
+ next(s, r)
+ slog.Info(
+ "Http request",
+ "method", r.Method,
+ "code", s.StatusCode(),
+ "path", r.URL,
+ "elapsed", time.Since(t),
+ )
+ }
+}
diff --git a/pkg/ext/router.go b/pkg/ext/router.go
new file mode 100644
index 0000000..5d22814
--- /dev/null
+++ b/pkg/ext/router.go
@@ -0,0 +1,72 @@
+package ext
+
+import (
+ "errors"
+ "fmt"
+ "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.RepositoryNotFoundErr) {
+ NotFound(w)
+ } else {
+ InternalServerError(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) {
+ w.WriteHeader(http.StatusNotFound)
+ templates.WritePageTemplate(w, &templates.ErrorPage{
+ Message: "Not Found",
+ })
+}
+
+func InternalServerError(w http.ResponseWriter, err error) {
+ w.WriteHeader(http.StatusInternalServerError)
+ templates.WritePageTemplate(w, &templates.ErrorPage{
+ Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
+ })
+}