Organizing Routes and Handlers
Learning Objectives
- Understand why organizing routes and handlers into a separate file improves code structure
- Learn how to create a
routes()method that returns anhttp.Handler - Understand what the
http.Handlerinterface is and how ServeMux implements it - Practice moving handlers from main.go to a dedicated routes.go file
- See how this pattern scales as your application grows
Introduction
In this one, you're gonna organize your routes and handlers by moving them out of main.go and into a separate routes.go file. You'll create a routes() method on your App struct that sets up all your HTTP routes and returns a handler. This keeps your main function focused on startup logic and makes it easier to manage routes as your application grows.
Theory/Concept
Why separate routes from main?
Right now, all your routes and handlers are sitting in main.go alongside database setup and server startup. That works for small apps, but as you add more routes, your main function becomes cluttered. By moving routes to their own file, you create a clear separation: main.go handles startup, routes.go handles routing.
The http.Handler interface:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
In Go, an http.Handler is any type that has a ServeHTTP() method. It's the interface the HTTP server uses to process requests. Your ServeMux (created with http.NewServeMux()) is a built-in implementation of http.Handler that routes requests based on method and path patterns like "GET /books".
When you call http.ListenAndServe(":8080", handler), you're passing an http.Handler. The server calls ServeHTTP() on that handler for every incoming request, and your ServeMux figures out which registered handler function to call.
Creating the routes method:
// File: cmd/api/routes.go
func (app *App) routes() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("GET /healthz", app.healthcheckHandler)
mux.HandleFunc("GET /books", app.listBooksHandler)
return mux
}
This method creates a new ServeMux, registers all your routes, and returns it. Because ServeMux implements http.Handler, you can return it directly. The method is attached to App so it has access to app.DB and any other dependencies you might add later.
Updating main to use routes():
// File: cmd/api/main.go
app := &App{DB: db}
log.Println("starting server on :8080")
if err := http.ListenAndServe(":8080", app.routes()); err != nil {
log.Fatal(err)
}
Your main function becomes much cleaner. Instead of creating the mux and registering routes inline, you call app.routes() and pass the returned handler to ListenAndServe. All the routing logic is now in one place, making it easy to see all your routes at a glance.
Moving handlers to routes.go:
Both handlers move to routes.go alongside the routes() method. This keeps all your HTTP-related code together. Notice they're still methods on App - that's important because they need access to app.DB and other shared dependencies.
Why this pattern scales:
As you add more routes, you just add more mux.HandleFunc() calls in the routes() method. Want to add authentication middleware? You can wrap your mux or individual handlers. Need to group routes by version? You can create multiple muxes and combine them. The routes() method becomes your single source of truth for all routing logic.
File organization benefits:
main.go: Startup, database setup, server initializationroutes.go: All route registration and handler definitions- Clear separation makes it easier to find and modify code
- New developers can quickly understand your application structure
Key Takeaways
- The
http.Handlerinterface requires aServeHTTP()method - ServeMux implements this - Creating a
routes()method onAppcentralizes all route registration - Moving routes and handlers to a separate file keeps main.go focused on startup
- The
routes()method returns anhttp.Handlerthat can be passed directly toListenAndServe - This pattern makes it easy to add new routes and see all routing logic in one place
- Handlers stay as methods on
Appto maintain access to shared dependencies
Related Go Bytes
- Organizing Go Applications - Video | GitHub Repo
- The http.Handler Interface - Video | GitHub Repo
0 comments