From 30aeff2f3fa8d4cbcb360c9d492fcbef8ef51839 Mon Sep 17 00:00:00 2001 From: StarpTech Date: Wed, 24 Jan 2024 12:28:23 +0100 Subject: [PATCH 1/3] feat: allow custom playground path --- router/cmd/instance.go | 1 + router/core/router.go | 24 +++++++++++++++---- router/internal/graphiql/playgroundhandler.go | 9 ++----- router/pkg/config/config.go | 1 + 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/router/cmd/instance.go b/router/cmd/instance.go index c087a07e67..02fc2663ae 100644 --- a/router/cmd/instance.go +++ b/router/cmd/instance.go @@ -102,6 +102,7 @@ func NewRouter(params Params, additionalOptions ...core.Option) (*core.Router, e core.WithGraphQLPath(cfg.GraphQLPath), core.WithModulesConfig(cfg.Modules), core.WithGracePeriod(cfg.GracePeriod), + core.WithPlaygroundPath(cfg.PlaygroundPath), core.WithHealthCheckPath(cfg.HealthCheckPath), core.WithLivenessCheckPath(cfg.LivenessCheckPath), core.WithGraphQLMetrics(&core.GraphQLMetricsConfig{ diff --git a/router/core/router.go b/router/core/router.go index 6c5aed0f6b..92fbacd66f 100644 --- a/router/core/router.go +++ b/router/core/router.go @@ -89,6 +89,7 @@ type ( listenAddr string baseURL string graphqlWebURL string + playgroundPath string graphqlPath string playground bool introspection bool @@ -173,6 +174,10 @@ func NewRouter(opts ...Option) (*Router, error) { r.graphqlWebURL = r.graphqlPath } + if r.playgroundPath == "" { + r.playgroundPath = "/" + } + // Default values for trace and metric config if r.traceConfig == nil { @@ -870,7 +875,7 @@ func (r *Router) newServer(ctx context.Context, routerConfig *nodev1.RouterConfi var graphqlPlaygroundHandler func(http.Handler) http.Handler if r.playground { - r.logger.Info("Serving GraphQL playground", zap.String("url", r.baseURL)) + r.logger.Info("Serving GraphQL playground", zap.String("url", r.baseURL+r.playgroundPath)) graphqlPlaygroundHandler = graphiql.NewPlayground(&graphiql.PlaygroundOptions{ Log: r.logger, Html: graphiql.PlaygroundHTML(), @@ -925,17 +930,19 @@ func (r *Router) newServer(ctx context.Context, routerConfig *nodev1.RouterConfi graphqlChiRouter := chi.NewRouter() // When the playground path is equal to the graphql path, we need to handle - // ws upgrades and html requests on the same route - if r.playground && r.graphqlPath == "/" { + // ws upgrades and html requests on the same route. + if r.playground && r.graphqlPath == r.playgroundPath { graphqlChiRouter.Use(graphqlPlaygroundHandler, wsMiddleware) } else { if r.playground { - httpRouter.Get("/", graphqlPlaygroundHandler(nil).ServeHTTP) + httpRouter.Get(r.playgroundPath, graphqlPlaygroundHandler(nil).ServeHTTP) } graphqlChiRouter.Use(wsMiddleware) } graphqlChiRouter.Use(graphqlPreHandler.Handler) + + // Built in and custom modules graphqlChiRouter.Use(r.routerMiddlewares...) graphqlChiRouter.Post("/", graphqlHandler.ServeHTTP) @@ -1117,7 +1124,7 @@ func WithCors(corsOpts *cors.Config) Option { } } -// WithGraphQLPath sets the path to the GraphQL endpoint. +// WithGraphQLPath sets the path where the GraphQL endpoint is served. func WithGraphQLPath(p string) Option { return func(r *Router) { r.graphqlPath = p @@ -1133,6 +1140,13 @@ func WithGraphQLWebURL(p string) Option { } } +// WithPlaygroundPath sets the path where the GraphQL Playground is served. +func WithPlaygroundPath(p string) Option { + return func(r *Router) { + r.playgroundPath = p + } +} + func WithConfigPoller(cf configpoller.ConfigPoller) Option { return func(r *Router) { r.configPoller = cf diff --git a/router/internal/graphiql/playgroundhandler.go b/router/internal/graphiql/playgroundhandler.go index fbc6ac00fd..f124804169 100644 --- a/router/internal/graphiql/playgroundhandler.go +++ b/router/internal/graphiql/playgroundhandler.go @@ -29,9 +29,8 @@ func NewPlayground(opts *PlaygroundOptions) func(http.Handler) http.Handler { func (p *Playground) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Only serve the playground if the request is for text/html - // This is especially important for Upgrade websocket requests - // when the graphql endpoint is on the same path as the playground - if isWsUpgradeRequest(r) || !strings.Contains(r.Header.Get("Accept"), "text/html") { + // if not, just pass through to the next handler + if !strings.Contains(strings.ToLower(r.Header.Get("Accept")), "text/html") { if p.next != nil { p.next.ServeHTTP(w, r) } @@ -47,7 +46,3 @@ func (p *Playground) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write(resp) } - -func isWsUpgradeRequest(r *http.Request) bool { - return r.Header.Get("Upgrade") == "websocket" -} diff --git a/router/pkg/config/config.go b/router/pkg/config/config.go index 3d46d7ec50..cd7a12b3d6 100644 --- a/router/pkg/config/config.go +++ b/router/pkg/config/config.go @@ -246,6 +246,7 @@ type Config struct { ReadinessCheckPath string `yaml:"readiness_check_path" default:"/health/ready" envconfig:"READINESS_CHECK_PATH" validate:"uri"` LivenessCheckPath string `yaml:"liveness_check_path" default:"/health/live" envconfig:"LIVENESS_CHECK_PATH" validate:"uri"` GraphQLPath string `yaml:"graphql_path" default:"/graphql" envconfig:"GRAPHQL_PATH"` + PlaygroundPath string `yaml:"playground_path" default:"/" envconfig:"PLAYGROUND_PATH"` Authentication AuthenticationConfiguration `yaml:"authentication"` Authorization AuthorizationConfiguration `yaml:"authorization"` LocalhostFallbackInsideDocker bool `yaml:"localhost_fallback_inside_docker" default:"true" envconfig:"LOCALHOST_FALLBACK_INSIDE_DOCKER"` From 30e509e3abba54647285468fcdd2478fc7146767 Mon Sep 17 00:00:00 2001 From: StarpTech Date: Wed, 24 Jan 2024 12:42:54 +0100 Subject: [PATCH 2/3] chore: improve --- router/core/router.go | 13 +++++++++++-- router/pkg/config/config.go | 10 +++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/router/core/router.go b/router/core/router.go index 92fbacd66f..b64395041b 100644 --- a/router/core/router.go +++ b/router/core/router.go @@ -875,7 +875,11 @@ func (r *Router) newServer(ctx context.Context, routerConfig *nodev1.RouterConfi var graphqlPlaygroundHandler func(http.Handler) http.Handler if r.playground { - r.logger.Info("Serving GraphQL playground", zap.String("url", r.baseURL+r.playgroundPath)) + playgroundUrl, err := url.JoinPath(r.baseURL, r.playgroundPath) + if err != nil { + return nil, fmt.Errorf("failed to join playground url: %w", err) + } + r.logger.Info("Serving GraphQL playground", zap.String("url", playgroundUrl)) graphqlPlaygroundHandler = graphiql.NewPlayground(&graphiql.PlaygroundOptions{ Log: r.logger, Html: graphiql.PlaygroundHTML(), @@ -950,9 +954,14 @@ func (r *Router) newServer(ctx context.Context, routerConfig *nodev1.RouterConfi // Serve GraphQL. MetricStore are collected after the request is handled and classified as r GraphQL request. httpRouter.Mount(r.graphqlPath, graphqlChiRouter) + graphqlEndpointURL, err := url.JoinPath(r.baseURL, r.graphqlPath) + if err != nil { + return nil, fmt.Errorf("failed to join graphql endpoint url: %w", err) + } + r.logger.Info("GraphQL endpoint", zap.String("method", http.MethodPost), - zap.String("url", r.baseURL+r.graphqlPath), + zap.String("url", graphqlEndpointURL), ) ro.server = &http.Server{ diff --git a/router/pkg/config/config.go b/router/pkg/config/config.go index cd7a12b3d6..067cee28b5 100644 --- a/router/pkg/config/config.go +++ b/router/pkg/config/config.go @@ -242,11 +242,11 @@ type Config struct { ShutdownDelay time.Duration `yaml:"shutdown_delay" default:"60s" validate:"required,min=15s" envconfig:"SHUTDOWN_DELAY"` GracePeriod time.Duration `yaml:"grace_period" default:"20s" validate:"required" envconfig:"GRACE_PERIOD"` PollInterval time.Duration `yaml:"poll_interval" default:"10s" validate:"required,min=5s" envconfig:"POLL_INTERVAL"` - HealthCheckPath string `yaml:"health_check_path" default:"/health" envconfig:"HEALTH_CHECK_PATH" validate:"uri"` - ReadinessCheckPath string `yaml:"readiness_check_path" default:"/health/ready" envconfig:"READINESS_CHECK_PATH" validate:"uri"` - LivenessCheckPath string `yaml:"liveness_check_path" default:"/health/live" envconfig:"LIVENESS_CHECK_PATH" validate:"uri"` - GraphQLPath string `yaml:"graphql_path" default:"/graphql" envconfig:"GRAPHQL_PATH"` - PlaygroundPath string `yaml:"playground_path" default:"/" envconfig:"PLAYGROUND_PATH"` + HealthCheckPath string `yaml:"health_check_path" default:"/health" validate:"uri" envconfig:"HEALTH_CHECK_PATH" validate:"uri"` + ReadinessCheckPath string `yaml:"readiness_check_path" default:"/health/ready" validate:"uri" envconfig:"READINESS_CHECK_PATH" validate:"uri"` + LivenessCheckPath string `yaml:"liveness_check_path" default:"/health/live" validate:"uri" envconfig:"LIVENESS_CHECK_PATH" validate:"uri"` + GraphQLPath string `yaml:"graphql_path" default:"/graphql" validate:"uri" envconfig:"GRAPHQL_PATH"` + PlaygroundPath string `yaml:"playground_path" default:"/" validate:"uri" envconfig:"PLAYGROUND_PATH"` Authentication AuthenticationConfiguration `yaml:"authentication"` Authorization AuthorizationConfiguration `yaml:"authorization"` LocalhostFallbackInsideDocker bool `yaml:"localhost_fallback_inside_docker" default:"true" envconfig:"LOCALHOST_FALLBACK_INSIDE_DOCKER"` From cb35b28a39001da5bc9acaefb9c6bb8f522dff02 Mon Sep 17 00:00:00 2001 From: StarpTech Date: Wed, 24 Jan 2024 12:49:35 +0100 Subject: [PATCH 3/3] chore: improve --- router/pkg/config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/router/pkg/config/config.go b/router/pkg/config/config.go index 067cee28b5..4d57f5bc58 100644 --- a/router/pkg/config/config.go +++ b/router/pkg/config/config.go @@ -242,9 +242,9 @@ type Config struct { ShutdownDelay time.Duration `yaml:"shutdown_delay" default:"60s" validate:"required,min=15s" envconfig:"SHUTDOWN_DELAY"` GracePeriod time.Duration `yaml:"grace_period" default:"20s" validate:"required" envconfig:"GRACE_PERIOD"` PollInterval time.Duration `yaml:"poll_interval" default:"10s" validate:"required,min=5s" envconfig:"POLL_INTERVAL"` - HealthCheckPath string `yaml:"health_check_path" default:"/health" validate:"uri" envconfig:"HEALTH_CHECK_PATH" validate:"uri"` - ReadinessCheckPath string `yaml:"readiness_check_path" default:"/health/ready" validate:"uri" envconfig:"READINESS_CHECK_PATH" validate:"uri"` - LivenessCheckPath string `yaml:"liveness_check_path" default:"/health/live" validate:"uri" envconfig:"LIVENESS_CHECK_PATH" validate:"uri"` + HealthCheckPath string `yaml:"health_check_path" default:"/health" envconfig:"HEALTH_CHECK_PATH" validate:"uri"` + ReadinessCheckPath string `yaml:"readiness_check_path" default:"/health/ready" envconfig:"READINESS_CHECK_PATH" validate:"uri"` + LivenessCheckPath string `yaml:"liveness_check_path" default:"/health/live" envconfig:"LIVENESS_CHECK_PATH" validate:"uri"` GraphQLPath string `yaml:"graphql_path" default:"/graphql" validate:"uri" envconfig:"GRAPHQL_PATH"` PlaygroundPath string `yaml:"playground_path" default:"/" validate:"uri" envconfig:"PLAYGROUND_PATH"` Authentication AuthenticationConfiguration `yaml:"authentication"`