homelabby/internal/api/router.go
Mikkel Georgsen 59aa89b199 feat(02-03): wire POST /api/intake route, real WAQ handler, and NetBox defaults in config
- router.go: NewRouter accepts intakeHandler http.Handler, registers POST /api/intake
- config.go: adds NetBoxDefaultDeviceTypeID/RoleID/SiteID fields with defaults and env bindings
- main.go: creates netbox.Client, ai.Orchestrator, inventory.CatalogUpdater, handlers.IntakeHandler
- main.go: replaces NoOpHandler with NewNetBoxOpHandler(nbClient) for WAQ worker
- main.go: uses typed interface variable for WAQ to avoid nil-interface-wrapping bug
2026-04-10 05:55:41 +00:00

51 lines
1.4 KiB
Go

package api
import (
"io/fs"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"git.georgsen.dk/hwlab/internal/api/handlers"
)
// spaHandler serves static files and falls back to index.html for unknown paths,
// enabling client-side routing in the React SPA.
type spaHandler struct {
staticFS fs.FS
}
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Try to open the requested path in the embedded FS.
f, err := h.staticFS.Open(r.URL.Path)
if err != nil {
// File not found — serve index.html so the SPA router handles it.
r2 := r.Clone(r.Context())
r2.URL.Path = "/"
http.FileServer(http.FS(h.staticFS)).ServeHTTP(w, r2)
return
}
f.Close()
http.FileServer(http.FS(h.staticFS)).ServeHTTP(w, r)
}
// NewRouter creates the chi router. staticFiles is the fs.FS rooted at web/dist,
// passed from main.go where the go:embed directive lives.
// intakeHandler handles POST /api/intake (multipart photo upload).
func NewRouter(staticFiles fs.FS, intakeHandler http.Handler) http.Handler {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RealIP)
r.Route("/api", func(r chi.Router) {
r.Get("/health", handlers.Health)
r.Post("/intake", intakeHandler.ServeHTTP)
})
// SPA fallback — serve static files; unknown paths fall back to index.html.
r.Handle("/*", spaHandler{staticFS: staticFiles})
return r
}