From 71e32f1fd7e083c906fc82b595ca233492a41983 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Sat, 14 Jun 2025 12:30:17 -0700 Subject: [PATCH] (FIX): Created a decent dependency inject architecture. The system allows services and repositories to be created in the main server definition and then store them in the context. They can then be retrieved and mapped onto the injection type and accessed in the handlers. The handlers can then use the deps to call services. Each service is initialized with the required repositories so they can be accessed directly. --- cmd/web/main.go | 5 +++- go.mod | 1 + internal/app/server/middleware.go | 15 +++++++++++ internal/app/server/server.go | 41 +++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 internal/app/server/middleware.go diff --git a/cmd/web/main.go b/cmd/web/main.go index 505bf14..8f3951d 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -5,5 +5,8 @@ import "github.com/haydenhargreaves/Potion/internal/app/server" const PORT = 3000 func main() { - server.Init(PORT).ConfigureAuth().Setup().Start() + s := server.Init(PORT).ConfigureAuth().ConnectDatabase().Setup() + defer s.DB.Close() + + s.Start() } diff --git a/go.mod b/go.mod index 854e920..2676d96 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect diff --git a/internal/app/server/middleware.go b/internal/app/server/middleware.go new file mode 100644 index 0000000..e0d6cb3 --- /dev/null +++ b/internal/app/server/middleware.go @@ -0,0 +1,15 @@ +package server + +import ( + "github.com/gin-gonic/gin" + domain "github.com/haydenhargreaves/Potion/internal/domain/server" +) + +// DepedencyInjectionMiddleware injects the dependencies into the context set. This is a middleware +// that is used to apply the required services. +func DepedencyInjectionMiddleware(deps *domain.InjectedDependencies) gin.HandlerFunc { + return func(ctx *gin.Context) { + ctx.Set("deps", deps) + ctx.Next() + } +} diff --git a/internal/app/server/server.go b/internal/app/server/server.go index f705e29..e6db8d4 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -1,6 +1,7 @@ package server import ( + "database/sql" "fmt" "os" @@ -8,14 +9,20 @@ import ( "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/haydenhargreaves/Potion/internal/app/handlers" + "github.com/haydenhargreaves/Potion/internal/app/service" + domain "github.com/haydenhargreaves/Potion/internal/domain/server" "github.com/haydenhargreaves/Potion/internal/infrastructure/auth" + "github.com/haydenhargreaves/Potion/internal/infrastructure/database/repository" "github.com/joho/godotenv" + + _ "github.com/lib/pq" ) type Server struct { port int Router *gin.Engine config cors.Config + DB *sql.DB } // Init initializes the server with the provided port. CORS settings are defined here. @@ -66,12 +73,46 @@ func (s *Server) ConfigureAuth() *Server { return s } +func (s *Server) ConnectDatabase() *Server { + err := godotenv.Load(".env") + if err != nil { + panic("Could not load env file") + } + + var connUrl string = os.Getenv("DATABASE_URL") + + db, err := sql.Open("postgres", connUrl) + if err != nil { + panic("Could not connect to database: " + err.Error()) + } + + if err = db.Ping(); err != nil { + panic("Error pinging database: " + err.Error()) + } + + s.DB = db + + return s +} + // Start starts the server on the port provided when the server was initialized func (s *Server) Start() { s.Router.Run(fmt.Sprintf(":%d", s.port)) } func (s *Server) Setup() *Server { + // Initialize and inject dependencies + userRepo := repository.NewUserRepository(s.DB) + userService := service.NewUserService(userRepo) + authService := service.NewAuthService(userRepo) + + deps := &domain.InjectedDependencies{ + UserService: userService, + AuthService: authService, + } + + s.Router.Use(DepedencyInjectionMiddleware(deps)) + // Wrap all routes with a version router_v1 := s.Router.Group("/v1")