refactor(api): centralize server setup in NewAPIServer

Refactored the API server setup to improve modularity and simplify the main application entry point.

- Created a new `NewAPIServer` function in `cmd/api/server.go` that encapsulates the creation and configuration of the `http.ServeMux`.
- This new function now handles the registration of all API routes, including the GraphQL endpoint (`/query`), the GraphQL Playground (`/playground`), and the Prometheus metrics endpoint (`/metrics`).
- Simplified `cmd/api/main.go` by removing the manual `ServeMux` creation and instead calling the new `NewAPIServer` function.
- This change makes the `main` function cleaner and more focused on its core responsibilities of application initialization and graceful shutdown.
This commit is contained in:
google-labs-jules[bot] 2025-10-07 13:48:46 +00:00
parent ab0736ad05
commit b87580442a
2 changed files with 30 additions and 23 deletions

View File

@ -23,7 +23,6 @@ import (
"tercul/internal/platform/search" "tercul/internal/platform/search"
"time" "time"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/pressly/goose/v3" "github.com/pressly/goose/v3"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/weaviate/weaviate-go-client/v5/weaviate" "github.com/weaviate/weaviate-go-client/v5/weaviate"
@ -156,19 +155,13 @@ func main() {
App: application, App: application,
} }
// Create the main API handler with all middleware. // Create the consolidated API server with all routes.
apiHandler := NewServerWithAuth(resolver, jwtManager, metrics, obsLogger) apiHandler := NewAPIServer(resolver, jwtManager, metrics, obsLogger, reg)
// Create the main ServeMux and register all handlers. // Create the main HTTP server.
mux := http.NewServeMux()
mux.Handle("/query", apiHandler)
mux.Handle("/playground", playground.Handler("GraphQL Playground", "/query"))
mux.Handle("/metrics", observability.PrometheusHandler(reg))
// Create a single HTTP server with the main mux.
mainServer := &http.Server{ mainServer := &http.Server{
Addr: cfg.ServerPort, Addr: cfg.ServerPort,
Handler: mux, Handler: apiHandler,
} }
app_log.Info(fmt.Sprintf("API server listening on port %s", cfg.ServerPort)) app_log.Info(fmt.Sprintf("API server listening on port %s", cfg.ServerPort))

View File

@ -7,28 +7,42 @@ import (
"tercul/internal/platform/auth" "tercul/internal/platform/auth"
"github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/prometheus/client_golang/prometheus"
) )
// NewServerWithAuth creates a new GraphQL server with authentication and observability middleware // NewAPIServer creates a new http.ServeMux and configures it with all the API routes,
func NewServerWithAuth(resolver *graphql.Resolver, jwtManager *auth.JWTManager, metrics *observability.Metrics, logger *observability.Logger) http.Handler { // including the GraphQL endpoint, GraphQL Playground, and Prometheus metrics.
func NewAPIServer(
resolver *graphql.Resolver,
jwtManager *auth.JWTManager,
metrics *observability.Metrics,
logger *observability.Logger,
reg *prometheus.Registry,
) *http.ServeMux {
// Configure the GraphQL server
c := graphql.Config{Resolvers: resolver} c := graphql.Config{Resolvers: resolver}
c.Directives.Binding = graphql.Binding c.Directives.Binding = graphql.Binding
// Create the server with the custom error presenter // Create the core GraphQL handler
srv := handler.NewDefaultServer(graphql.NewExecutableSchema(c)) graphqlHandler := handler.NewDefaultServer(graphql.NewExecutableSchema(c))
srv.SetErrorPresenter(graphql.NewErrorPresenter()) graphqlHandler.SetErrorPresenter(graphql.NewErrorPresenter())
// Create a middleware chain. The order is important. // Create the middleware chain for the GraphQL endpoint.
// Middlewares are applied from bottom to top, so the last one added is the first to run. // Middlewares are applied from bottom to top.
var chain http.Handler var chain http.Handler
chain = srv chain = graphqlHandler
chain = metrics.PrometheusMiddleware(chain) chain = metrics.PrometheusMiddleware(chain)
// LoggingMiddleware needs to run after auth and tracing to get all context. chain = observability.LoggingMiddleware(logger)(chain) // Must run after auth and tracing
chain = observability.LoggingMiddleware(logger)(chain)
chain = auth.GraphQLAuthMiddleware(jwtManager)(chain) chain = auth.GraphQLAuthMiddleware(jwtManager)(chain)
chain = observability.TracingMiddleware(chain) chain = observability.TracingMiddleware(chain)
chain = observability.RequestIDMiddleware(chain) chain = observability.RequestIDMiddleware(chain)
// Return the handler chain directly. The caller is responsible for routing. // Create a new ServeMux and register all handlers
return chain mux := http.NewServeMux()
mux.Handle("/query", chain)
mux.Handle("/playground", playground.Handler("GraphQL Playground", "/query"))
mux.Handle("/metrics", observability.PrometheusHandler(reg))
return mux
} }