go-mongo/router.go

105 lines
2.8 KiB
Go

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
}