joist/routing.go
2025-09-06 17:56:59 -04:00

93 lines
1.8 KiB
Go

package joist
import (
"context"
"log"
"net/http"
"regexp"
"strings"
"time"
jerr "git.markbailey.dev/cerbervs/joist/internal/errors"
"github.com/go-chi/chi/v5"
)
type RouteInfo struct {
Method string
Name string
Path string
Description string
Title string
}
func NewRouteInfo(method, path, description, title string) (RouteInfo, error) {
name, err := convertRouteToRouteName(path)
if err != nil {
return RouteInfo{}, err
}
return RouteInfo{
Method: method,
Name: name,
Path: path,
Description: description,
Title: title,
}, nil
}
type routeInfoKey struct{}
type Router struct {
chi.Mux
cache RouteCacher
cacheTTL time.Duration
}
func NewRouter() Router {
ttl := 8 * time.Hour
cache, err := NewRouteCacheService(WithTTL(ttl))
if err != nil {
log.Fatal(jerr.Wrap(err, jerr.ErrRouterNotCreated))
}
return Router{cache: cache, cacheTTL: ttl}
}
func (ro *Router) WithRouteInfo(ri RouteInfo, h HandlerFn) http.HandlerFunc {
ro.cache.AddRouteInfo(ri)
return func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), routeInfoKey{}, ri)
h.ServeHTTP(w, r.WithContext(ctx))
}
}
// TODO: move to base handler when it's implemented
func GetRouteInfo(r *http.Request) (RouteInfo, bool) {
info, ok := r.Context().Value(routeInfoKey{}).(RouteInfo)
return info, ok
}
func convertRouteToRouteName(route string) (string, error) {
name := "app"
if route == "/" {
return name + ".home", nil
}
route = strings.ReplaceAll(route, "/", ".")
route = strings.ReplaceAll(route, "-", "_")
paramRegex := regexp.MustCompile(`\.{[^}]*}`)
params := paramRegex.FindAllString(route, -1)
route = paramRegex.ReplaceAllString(route, "")
if len(params) > 0 {
route += ".params"
}
name += strings.TrimRight(route, ".")
return name, nil
}