tercul-backend/cmd/api/server.go
google-labs-jules[bot] 53aa4d0344
Security Hardening and GraphQL Caching (#69)
* feat: add security middleware, graphql apq, and improved linting

- Add RateLimit, RequestValidation, and CORS middleware.
- Configure middleware chain in API server.
- Implement Redis cache for GraphQL Automatic Persisted Queries.
- Add .golangci.yml and fix linting issues (shadowing, timeouts).

* feat: security, caching and linting config

- Fix .golangci.yml config for govet shadow check
- (Previous changes: Security middleware, GraphQL APQ, Linting fixes)

* fix: resolve remaining lint errors

- Fix unhandled errors in tests (errcheck)
- Define constants for repeated strings (goconst)
- Suppress high complexity warnings with nolint:gocyclo
- Fix integer overflow warnings (gosec)
- Add package comments
- Split long lines (lll)
- Rename Analyse -> Analyze (misspell)
- Fix naked returns and unused params

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2025-12-01 00:14:22 +01:00

72 lines
2.3 KiB
Go

package main
import (
"net/http"
"tercul/internal/adapters/graphql"
"tercul/internal/observability"
"tercul/internal/platform/auth"
"tercul/internal/platform/config"
platform_http "tercul/internal/platform/http"
gql "github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/prometheus/client_golang/prometheus"
)
// NewAPIServer creates a new http.ServeMux and configures it with all the API routes,
// including the GraphQL endpoint, GraphQL Playground, and Prometheus metrics.
func NewAPIServer(
cfg *config.Config,
resolver *graphql.Resolver,
queryCache gql.Cache[string],
jwtManager *auth.JWTManager,
metrics *observability.Metrics,
logger *observability.Logger,
reg *prometheus.Registry,
) *http.ServeMux {
// Configure the GraphQL server
c := graphql.Config{Resolvers: resolver}
c.Directives.Binding = graphql.Binding
// Create the core GraphQL handler
graphqlHandler := handler.New(graphql.NewExecutableSchema(c))
// Enable Automatic Persisted Queries (APQ) if cache is provided
if queryCache != nil {
graphqlHandler.Use(extension.AutomaticPersistedQuery{
Cache: queryCache,
})
}
graphqlHandler.SetErrorPresenter(graphql.NewErrorPresenter())
// Create the middleware chain for the GraphQL endpoint.
// Middlewares are applied from bottom to top (last applied is first executed).
var chain http.Handler
chain = graphqlHandler
chain = metrics.PrometheusMiddleware(chain)
chain = observability.LoggingMiddleware(logger)(chain) // Must run after auth and tracing
chain = auth.GraphQLAuthMiddleware(jwtManager)(chain)
chain = observability.TracingMiddleware(chain)
chain = observability.RequestIDMiddleware(chain)
// Security and Validation Middlewares
chain = platform_http.RequestValidationMiddleware(chain)
chain = platform_http.RateLimitMiddleware(cfg)(chain)
// CORS should be the outermost to handle preflight OPTIONS requests
// TODO: Make allowed origins configurable
chain = platform_http.CORSMiddleware([]string{"*"})(chain)
// Create a new ServeMux and register all handlers
mux := http.NewServeMux()
mux.Handle("/query", chain)
mux.Handle("/playground", playground.Handler("GraphQL Playground", "/query"))
mux.Handle("/metrics", observability.PrometheusHandler(reg))
return mux
}