package main import ( "log" "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" "git.farahty.com/nimer/go-mongo/helpers" "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) router.Use(app.WriterMiddleware) // 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 { cache, err := helpers.NewCache(redisClient, 24*time.Hour, "apq:") if err != nil { log.Fatalf("cannot create APQ redis cache: %v", err) } // 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{}) srv.Use(extension.AutomaticPersistedQuery{Cache: cache}) 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 }