package main import ( "context" "fmt" "net/http" "path/filepath" "regexp" "slices" ) type URLParam struct{} type W = http.ResponseWriter type R = *http.Request var routes = []struct { methods []string regex *regexp.Regexp handler http.HandlerFunc }{ {[]string{"GET"}, URL(""), func(w W, r R) { http.ServeFile(w, r, filepath.Join("html", "index.html")) }}, {[]string{"GET"}, URL("/style\\.css"), func(w W, r R) { http.ServeFile(w, r, "/html/style.css") }}, {[]string{"GET"}, URL("/static/.+"), func(w W, r R) { http.ServeFile(w, r, r.URL.Path) }}, {[]string{"GET"}, URL("/[^/]+"), func(w W, r R) { http.ServeFile(w, r, filepath.Join("html", r.URL.Path + ".html")) }}, } func URL(s string) *regexp.Regexp { return regexp.MustCompile("^" + s + "/?$") } func Route(w http.ResponseWriter, r *http.Request) { for _, rt := range routes { matches := rt.regex.FindStringSubmatch(r.URL.Path) if len(matches) > 0 { if !slices.Contains(rt.methods, r.Method) { w.Header().Set("Allow", r.Method) http.Error( w, "405 method not allowed", http.StatusMethodNotAllowed, ) fmt.Println(r.Method, r.URL.Path) } rt.handler(w, r.WithContext( context.WithValue(r.Context(), URLParam{}, matches[1:])), ) return } } http.NotFound(w, r) }