101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
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
|
|
}
|