package main import ( "net/http" "os" "time" "git.farahty.com/nimer/go-mongo/app" "git.farahty.com/nimer/go-mongo/controllers" "git.farahty.com/nimer/go-mongo/directives" "git.farahty.com/nimer/go-mongo/generated" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler/extension" "github.com/99designs/gqlgen/graphql/handler/transport" "github.com/99designs/gqlgen/graphql/playground" "git.farahty.com/nimer/go-mongo/resolvers" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/httprate" "github.com/gorilla/websocket" "github.com/redis/go-redis/v9" ) func createRouter(graphqlServer http.Handler) chi.Router { router := chi.NewRouter() // Apply middleware if os.Getenv("ENV") == "production" { router.Use(httprate.LimitByIP(100, 1*time.Minute)) // 100 requests/minute/IP } router.Use(middleware.Logger) router.Use(middleware.StripSlashes) router.Use(middleware.RealIP) router.Use(middleware.Recoverer) // Custom middleware for Auth router.Use(app.AuthMiddleware) // REST routes router.Mount("/users", controllers.UserRouter()) // GraphQL endpoints router.Handle("/", playground.Handler("GraphQL Playground", "/graphql")) router.Handle("/graphql", graphqlServer) return router } func createGraphqlServer(redisClient *redis.Client) http.Handler { // Setup gqlgen with resolvers and Redis client schema := generated.Config{ Resolvers: &resolvers.Resolver{ Redis: redisClient, }, } // Map directives (e.g., @auth) mapDirectives(&schema) // Initialize GraphQL handler srv := handler.New(generated.NewExecutableSchema(schema)) // Enable transports (WebSocket, GET, POST, etc.) srv.AddTransport(transport.Websocket{ KeepAlivePingInterval: 10 * time.Second, Upgrader: websocket.Upgrader{ HandshakeTimeout: time.Minute, EnableCompression: true, CheckOrigin: func(r *http.Request) bool { return true }, }, InitFunc: app.AuthorizeWebSocket, }) srv.AddTransport(transport.Options{}) srv.AddTransport(transport.GET{}) srv.AddTransport(transport.POST{}) srv.AddTransport(transport.MultipartForm{}) // Optional: Enable persisted queries or caching // srv.Use(extension.AutomaticPersistedQuery{ // Cache: lru.New(100), // }) // srv.SetQueryCache(lru.New(1000)) // Enable introspection for Playground srv.Use(extension.Introspection{}) // Apply global middleware srv.AroundRootFields(app.RootFieldsAuthorizer) // Check for @auth at root fields srv.AroundResponses(app.ExpiryMiddleware) // Token expiry validation // Inject DataLoaders into request context return app.LoaderMiddleware(app.NewLoaders(), srv) } func mapDirectives(config *generated.Config) { config.Directives.Auth = directives.Auth }