Optimizing Route Registration for a Big Project: Modular Monolith with go-chi & Clean Architecture #991
Replies: 1 comment
|
Your current pattern is solid and aligns well with clean architecture + modular monolith principles. A few refinements that scale better for large projects: 1. Separate dependency wiring from route registration Your // handlers/users/handler.go
type UserHandler struct {
service *application.UserService
}
func NewUserHandler(svc *application.UserService) *UserHandler {
return &UserHandler{service: svc}
}
func (h *UserHandler) Routes() chi.Router {
r := chi.NewRouter()
r.Post("/", h.RegisterUser)
r.Get("/{id}", h.GetUser)
return r
}Then in func buildRouter(db *sqlx.DB) chi.Router {
r := chi.NewRouter()
r.Use(middleware.Logger, middleware.Recoverer)
// Dependency wiring happens here
userRepo := userdb.NewUserRepo(db)
userSvc := application.NewUserService(userRepo)
userHandler := users.NewUserHandler(userSvc)
categoryRepo := categorydb.NewCategoryRepo(db)
categorySvc := categoryapp.NewCategoryService(categoryRepo)
categoryHandler := categories.NewCategoryHandler(categorySvc)
// Route mounting
r.Mount("/users", userHandler.Routes())
r.Mount("/categories", categoryHandler.Routes())
return r
}2. Use Each module returns a 3. For complex dependency graphs, use Wire or Fx If dependencies start having many layers (repo → service → handler → middleware), google/wire generates the wiring code at compile time. uber-go/fx does it at runtime with a DI container. Summary Your structure is fine. The main improvement is moving dependency construction to one place ( |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hey everyone,
I'm building a backend API using go-chi and aiming to follow clean architecture principles while maintaining a modular monolith structure. My application includes many different endpoints (like product, category, payment, shipping, etc.), and I'm looking for the best way to register routes in a clean and maintainable manner. and to handle the dependency management and passing it to the down steam components
Currently, I'm using a pattern where the route registration function is part of the handler itself. For example, in my user module, I have a function inside the handlers package that initializes dependencies and registers the route:
In this setup, each module manages its own dependencies and route registration, which keeps the codebase modular and aligns with clean architecture principles.
For context, my project structure is organized like this:
My Questions for the Community:
I’d really appreciate your insights, alternative strategies, or improvements based on your experiences. Thanks in advance for your help
All reactions