package http import ( "strings" "github.com/gofiber/fiber/v3" "knowfoolery/backend/services/gateway-service/internal/infra/proxy" "knowfoolery/backend/services/gateway-service/internal/infra/routing" ) // Options defines route wiring dependencies. type Options struct { PublicPrefix string Upstreams routing.Upstreams Proxy *proxy.ReverseProxy AuthMiddleware fiber.Handler RateLimitMiddleware fiber.Handler } // RegisterRoutes registers gateway forwarding routes. func RegisterRoutes(app *fiber.App, opts Options) { prefix := normalizePrefix(opts.PublicPrefix) api := app.Group(prefix) if opts.RateLimitMiddleware != nil { api.Use(opts.RateLimitMiddleware) } if opts.AuthMiddleware != nil { api.Use(opts.AuthMiddleware) } // Question bank public routes. api.Post("/questions/random", forward(opts, opts.Upstreams.QuestionBank)) api.Get("/questions/:id", forward(opts, opts.Upstreams.QuestionBank)) api.Post("/questions/:id/validate-answer", forward(opts, opts.Upstreams.QuestionBank)) // Session routes. api.All("/sessions", forward(opts, opts.Upstreams.GameSession)) api.All("/sessions/*", forward(opts, opts.Upstreams.GameSession)) // User routes. api.All("/users", forward(opts, opts.Upstreams.User)) api.All("/users/*", forward(opts, opts.Upstreams.User)) // Leaderboard routes. api.Get("/leaderboard/top10", forward(opts, opts.Upstreams.Leaderboard)) api.Get("/leaderboard/stats", forward(opts, opts.Upstreams.Leaderboard)) api.Get("/leaderboard/players/:id", forward(opts, opts.Upstreams.Leaderboard)) api.Post("/leaderboard/update", forward(opts, opts.Upstreams.Leaderboard)) // Admin passthrough routes. api.All("/admin/questions", forward(opts, opts.Upstreams.QuestionBank)) api.All("/admin/questions/*", forward(opts, opts.Upstreams.QuestionBank)) api.All("/admin/themes", forward(opts, opts.Upstreams.QuestionBank)) api.All("/admin/themes/*", forward(opts, opts.Upstreams.QuestionBank)) api.All("/admin/users", forward(opts, opts.Upstreams.User)) api.All("/admin/users/*", forward(opts, opts.Upstreams.User)) api.Post("/admin/auth", forward(opts, opts.Upstreams.Admin)) api.Get("/admin/dashboard", forward(opts, opts.Upstreams.Admin)) api.Get("/admin/audit", forward(opts, opts.Upstreams.Admin)) } func forward(opts Options, upstream string) fiber.Handler { return func(c fiber.Ctx) error { targetPath := strings.TrimPrefix(c.Path(), normalizePrefix(opts.PublicPrefix)) if targetPath == "" { targetPath = "/" } return opts.Proxy.Forward(c, upstream, targetPath) } } func normalizePrefix(raw string) string { prefix := strings.TrimSpace(raw) if prefix == "" { prefix = "/api/v1" } if !strings.HasPrefix(prefix, "/") { prefix = "/" + prefix } return strings.TrimRight(prefix, "/") }