When related Go programs share libraries, putting each executable in its own cmd subdirectory keeps entry points distinct without separating the shared code. Each executable has a main package and main() function, such as cmd/api/main.go. This is a convention, not a required Go project layout. section 11.1.1 section 11.3.2
Keep the command focused on starting the program:
- Place startup code in cmd/api/main.go: initialize storage, construct handlers, register routes, and start the HTTP server. section 11.3.2
- Keep HTTP handlers in internal/handlers when they are used only by the API module; import the shared storage module rather than creating another store package. section 11.3.2
api/ ├── cmd/ │ └── api/ │ └── main.go #1 ├── internal/ │ └── handlers/ │ ├── handlers.go #2 │ └── handlers_test.go └── go.mod
The directory tree shows the command entry point alongside, rather than mixed with, the API module’s internal handlers. section 11.3.2
package main
import (
"fmt"
"log"
"net/http"
"github.com/YOUR_USERNAME/go-news/api/internal/handlers"
"github.com/YOUR_USERNAME/go-news/storage"
)
func main() {
store, err := storage.NewBoltStore("./articles.db", true) #1
if err != nil {
log.Fatalf("failed to initialize storage: %v", err)
}
defer store.Close() #2
h := handlers.New(store) #3
mux := http.NewServeMux() #4
h.RegisterRoutes(mux)
fmt.Println("Starting API server on :8080")
if err := http.ListenAndServe(":8080", mux); err != nil { #5
log.Fatal(err)
}
}
The main function shows the command wiring a shared store into handlers and starting the server. section 11.3.2
