๐ Routing in Go Using Chi
Chi is a lightweight, idiomatic, and composable router for building HTTP services in Go. This guide outlines best practices for structuring and implementing both public and protected routes in a Go application using Chi.
๐ Project Structure
Organize your project to keep route management clean and maintainable. A recommended structure is:
/cmd
โโโ main.go
/internal
โโโ routes/
โ โโโ public.go
โ โโโ private.go
โ โโโ register.go
โโโ handler/
โ โโโ auth/
โ โ โโโ register.go
โ โ โโโ login.go
โ โโโ post/
โโโ utils/
โโโ auth.go๐ Public Routes
Define routes that do not require authentication (e.g., login, registration) in public.go:
func PublicRoutes(r chi.Router) {
r.Post("/register", auth.RegisterHandler)
r.Post("/login", auth.LoginHandler)
r.Post("/refresh", auth.RefreshHandler)
r.Post("/forgot-password", auth.ForgotPasswordHandler)
r.Post("/reset-password", auth.ResetPasswordHandler)
}These endpoints are accessible without a token and are typically used for onboarding and recovery workflows.
๐ Protected Routes
Use route grouping to apply middleware (such as authentication) only where needed. Define protected routes in private.go:
func PrivateRoutes(r chi.Router) {
r.Group(func(r chi.Router) {
r.Use(utils.AuthMiddleware)
r.Post("/change-password", auth.ChangePasswordHandler)
r.Get("/users", auth.GetAllUsersHandler)
r.Get("/user/{email}", auth.GetUserByEmailHandler)
})
}The middleware utils.AuthMiddleware ensures that all routes in this group are only accessible to authenticated users.
๐ Combining Routes in register.go
In register.go, combine both public and protected routes for a unified setup:
func RegisterRoutes(r chi.Router) {
// Register public routes
PublicRoutes(r)
// Register protected routes
PrivateRoutes(r)
}๐ Entry Point โ main.go
Finally, wire everything together in your main application:
func main() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
routes.RegisterRoutes(r)
fmt.Println("Server running on http://localhost:8080")
http.ListenAndServe(":8080", r)
}This setup enables clean separation of concerns, security via middleware, and scalable route management as your application grows.
โ Final Thoughts
- Use
chi.Groupto isolate middleware (auth, logging, role-based access). - Separate route layers (
public,private,admin) as your app scales. - Keep handlers modular and organized under
/internal/handler.
For more advanced features like rate limiting or versioning (/api/v1), Chi supports nesting groups and composing middleware effectively.