router.gno

2.24 Kb ยท 98 lines
 1package mux
 2
 3import (
 4	"net/url"
 5	"strings"
 6)
 7
 8// Router handles the routing and rendering logic.
 9type Router struct {
10	routes          []Handler
11	NotFoundHandler NotFoundHandler
12}
13
14// NewRouter creates a new Router instance.
15func NewRouter() *Router {
16	return &Router{
17		routes:          make([]Handler, 0),
18		NotFoundHandler: defaultNotFoundHandler,
19	}
20}
21
22// Render renders the output for the given path using the registered route handler.
23func (r *Router) Render(reqPath string) string {
24	clearPath, rawQuery, _ := strings.Cut(reqPath, "?")
25	query, _ := url.ParseQuery(rawQuery)
26	reqParts := strings.Split(clearPath, "/")
27
28	for _, route := range r.routes {
29		patParts := strings.Split(route.Pattern, "/")
30		wildcard := false
31		for _, part := range patParts {
32			if part == "*" {
33				wildcard = true
34				break
35			}
36		}
37		if !wildcard && len(patParts) != len(reqParts) {
38			continue
39		}
40
41		match := true
42		for i := 0; i < len(patParts); i++ {
43			patPart := patParts[i]
44			reqPart := reqParts[i]
45
46			if patPart == "*" {
47				break
48			}
49			if strings.HasPrefix(patPart, "{") && strings.HasSuffix(patPart, "}") {
50				continue
51			}
52			if patPart != reqPart {
53				match = false
54				break
55			}
56		}
57		if match {
58			req := &Request{
59				Path:        clearPath,
60				RawPath:     reqPath,
61				HandlerPath: route.Pattern,
62				Query:       query,
63			}
64			res := &ResponseWriter{}
65			route.Fn(res, req)
66			return res.Output()
67		}
68	}
69
70	// not found
71	req := &Request{Path: reqPath, Query: query}
72	res := &ResponseWriter{}
73	r.NotFoundHandler(res, req)
74	return res.Output()
75}
76
77// HandleFunc registers a route and its handler function.
78func (r *Router) HandleFunc(pattern string, fn HandlerFunc) {
79	route := Handler{Pattern: pattern, Fn: fn}
80	r.routes = append(r.routes, route)
81}
82
83// HandleErrFunc registers a route and its error handler function.
84func (r *Router) HandleErrFunc(pattern string, fn ErrHandlerFunc) {
85	// Convert ErrHandlerFunc to regular HandlerFunc
86	handler := func(res *ResponseWriter, req *Request) {
87		if err := fn(res, req); err != nil {
88			res.Write("Error: " + err.Error())
89		}
90	}
91
92	r.HandleFunc(pattern, handler)
93}
94
95// SetNotFoundHandler sets custom message for 404 defaultNotFoundHandler.
96func (r *Router) SetNotFoundHandler(handler NotFoundHandler) {
97	r.NotFoundHandler = handler
98}