Skip to Content
Go Realm v1 is released ๐ŸŽ‰

๐Ÿ“˜ 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.Group to 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.