mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-19 06:27:38 +00:00
feat(deps)!: migrate from fiber v2 to fiber v3
BREAKING CHANGE: upgrades the HTTP framework from gofiber/fiber/v2 to gofiber/fiber/v3, and gofiber/websocket/v2 to gofiber/contrib/v3/websocket. - Handlers now take fiber.Ctx (interface) instead of *fiber.Ctx. - DisableStartupMessage moved from fiber.Config to fiber.ListenConfig on the proxy/api/monitoring Listen calls. - cors AllowOrigins is now []string; c.BodyParser -> c.Bind().Body(). - app.Test takes fiber.TestConfig instead of an int timeout (tests updated). - WebSocket swapped to contrib/v3/websocket (same Conn/New/Config/IsCloseError/IsWebSocketUpgrade API; Conn.Query preserved). - Adopts fasthttp v1.71.0 (pulled by fiber v3), resolving the v1.71 Host-header enforcement that broke the prior pinned-v1.69 workaround. fix(connpool): the background keep-alive goroutine no longer reads the mutable global cfg (captures HostGraphQL/HealthcheckGraphQL at pool creation). Under v3 timing it raced with parseConfig/test cfg reassignment; go test -race ./... is now clean (0 data races). test: make the circuit-breaker cache-fallback and request-coalescing integration tests deterministic (cache TTL outlives the retry loop; coalescing asserts against a measured single-request baseline instead of a hard-coded count); drop the flaky timing-ratio assertion in TestTimingAttackResistance (constant-time guarantee comes from subtle.ConstantTimeCompare, not wall-clock timing). Verified: go build, go vet, golangci-lint (0 issues), go test -race ./... (all packages pass, 0 races), govulncheck (no vulnerabilities). App + dashboard + WebSocket verified live under v3 in single-node and cluster modes.
This commit is contained in:
@@ -6,8 +6,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
fiber "github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
fiber "github.com/gofiber/fiber/v3"
|
||||
"github.com/gofiber/fiber/v3/middleware/cors"
|
||||
"github.com/google/uuid"
|
||||
|
||||
graphql "github.com/lukaszraczylo/go-simple-graphql"
|
||||
@@ -42,19 +42,18 @@ func StartHTTPProxy() error {
|
||||
})
|
||||
|
||||
serverConfig := fiber.Config{
|
||||
DisableStartupMessage: true,
|
||||
AppName: fmt.Sprintf("GraphQL Monitoring Proxy - %s v%s", libpack_config.PKG_NAME, libpack_config.PKG_VERSION),
|
||||
IdleTimeout: time.Duration(cfg.Client.ClientTimeout) * time.Second,
|
||||
ReadTimeout: time.Duration(cfg.Client.ClientTimeout) * time.Second,
|
||||
WriteTimeout: time.Duration(cfg.Client.ClientTimeout) * time.Second,
|
||||
JSONEncoder: json.Marshal,
|
||||
JSONDecoder: json.Unmarshal,
|
||||
AppName: fmt.Sprintf("GraphQL Monitoring Proxy - %s v%s", libpack_config.PKG_NAME, libpack_config.PKG_VERSION),
|
||||
IdleTimeout: time.Duration(cfg.Client.ClientTimeout) * time.Second,
|
||||
ReadTimeout: time.Duration(cfg.Client.ClientTimeout) * time.Second,
|
||||
WriteTimeout: time.Duration(cfg.Client.ClientTimeout) * time.Second,
|
||||
JSONEncoder: json.Marshal,
|
||||
JSONDecoder: json.Unmarshal,
|
||||
}
|
||||
|
||||
server := fiber.New(serverConfig)
|
||||
|
||||
server.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "*",
|
||||
AllowOrigins: []string{"*"},
|
||||
}))
|
||||
|
||||
server.Use(AddRequestUUID)
|
||||
@@ -71,7 +70,7 @@ func StartHTTPProxy() error {
|
||||
|
||||
// WebSocket support - must be registered before catch-all routes
|
||||
if cfg.WebSocket.Enable {
|
||||
server.Get("/v1/graphql", func(c *fiber.Ctx) error {
|
||||
server.Get("/v1/graphql", func(c fiber.Ctx) error {
|
||||
if IsWebSocketRequest(c) {
|
||||
wsp := GetWebSocketProxy()
|
||||
if wsp != nil {
|
||||
@@ -90,7 +89,7 @@ func StartHTTPProxy() error {
|
||||
Pairs: map[string]any{"port": cfg.Server.PortGraphQL},
|
||||
})
|
||||
|
||||
if err := server.Listen(fmt.Sprintf(":%d", cfg.Server.PortGraphQL)); err != nil {
|
||||
if err := server.Listen(fmt.Sprintf(":%d", cfg.Server.PortGraphQL), fiber.ListenConfig{DisableStartupMessage: true}); err != nil {
|
||||
return fmt.Errorf("failed to start HTTP proxy server on port %d: %w",
|
||||
cfg.Server.PortGraphQL, err)
|
||||
}
|
||||
@@ -99,18 +98,18 @@ func StartHTTPProxy() error {
|
||||
}
|
||||
|
||||
// proxyTheRequestToDefault proxies the request to the default GraphQL endpoint.
|
||||
func proxyTheRequestToDefault(c *fiber.Ctx) error {
|
||||
func proxyTheRequestToDefault(c fiber.Ctx) error {
|
||||
return proxyTheRequest(c, cfg.Server.HostGraphQL)
|
||||
}
|
||||
|
||||
// AddRequestUUID adds a unique request UUID to the context.
|
||||
func AddRequestUUID(c *fiber.Ctx) error {
|
||||
func AddRequestUUID(c fiber.Ctx) error {
|
||||
c.Locals("request_uuid", uuid.NewString())
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// checkAllowedURLs checks if the requested URL is allowed.
|
||||
func checkAllowedURLs(c *fiber.Ctx) bool {
|
||||
func checkAllowedURLs(c fiber.Ctx) bool {
|
||||
if len(allowedUrls) == 0 {
|
||||
return true
|
||||
}
|
||||
@@ -120,7 +119,7 @@ func checkAllowedURLs(c *fiber.Ctx) bool {
|
||||
}
|
||||
|
||||
// healthCheck performs a comprehensive health check on the GraphQL server and its dependencies.
|
||||
func healthCheck(c *fiber.Ctx) error {
|
||||
func healthCheck(c fiber.Ctx) error {
|
||||
// Prepare the response structure
|
||||
response := HealthCheckResponse{
|
||||
Status: "healthy",
|
||||
@@ -254,7 +253,7 @@ func healthCheck(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// processGraphQLRequest handles the incoming GraphQL requests.
|
||||
func processGraphQLRequest(c *fiber.Ctx) error {
|
||||
func processGraphQLRequest(c fiber.Ctx) error {
|
||||
startTime := time.Now()
|
||||
|
||||
// Extract user information and check permissions
|
||||
@@ -305,7 +304,7 @@ func processGraphQLRequest(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// extractUserInfo extracts user ID and role from request headers
|
||||
func extractUserInfo(c *fiber.Ctx) (string, string) {
|
||||
func extractUserInfo(c fiber.Ctx) (string, string) {
|
||||
extractedUserID := "-"
|
||||
extractedRoleName := "-"
|
||||
|
||||
@@ -326,7 +325,7 @@ func extractUserInfo(c *fiber.Ctx) (string, string) {
|
||||
}
|
||||
|
||||
// handleCaching manages the caching logic for GraphQL requests
|
||||
func handleCaching(c *fiber.Ctx, parsedResult *parseGraphQLQueryResult, userID, userRole string) (bool, error) {
|
||||
func handleCaching(c fiber.Ctx, parsedResult *parseGraphQLQueryResult, userID, userRole string) (bool, error) {
|
||||
// Calculate query hash for cache key - now includes user context for security
|
||||
calculatedQueryHash := libpack_cache.CalculateHash(c, userID, userRole)
|
||||
|
||||
@@ -380,7 +379,7 @@ func handleCaching(c *fiber.Ctx, parsedResult *parseGraphQLQueryResult, userID,
|
||||
}
|
||||
|
||||
// proxyAndCacheTheRequest proxies and caches the request if needed.
|
||||
func proxyAndCacheTheRequest(c *fiber.Ctx, queryCacheHash string, cacheTime int, currentEndpoint string) error {
|
||||
func proxyAndCacheTheRequest(c fiber.Ctx, queryCacheHash string, cacheTime int, currentEndpoint string) error {
|
||||
if err := proxyTheRequest(c, currentEndpoint); err != nil {
|
||||
cfg.Logger.Error(&libpack_logger.LogMessage{
|
||||
Message: "Can't proxy the request",
|
||||
@@ -396,7 +395,7 @@ func proxyAndCacheTheRequest(c *fiber.Ctx, queryCacheHash string, cacheTime int,
|
||||
}
|
||||
|
||||
// logAndMonitorRequest logs and monitors the request processing.
|
||||
func logAndMonitorRequest(c *fiber.Ctx, userID, opType, opName string, wasCached bool, duration time.Duration, startTime time.Time) {
|
||||
func logAndMonitorRequest(c fiber.Ctx, userID, opType, opName string, wasCached bool, duration time.Duration, startTime time.Time) {
|
||||
// Low-cardinality labels only: user_id and op_name dropped to prevent Prometheus explosion.
|
||||
labels := map[string]string{
|
||||
"op_type": opType,
|
||||
|
||||
Reference in New Issue
Block a user