This app loads application specific global configs and starts http server so that it is ready to serve API requests.
While structuring and coding, I've followed some "best" practises either from the official docs, widely followed resources and some others. Given that the app below works, I have a feeling that it could be improved hence reason I am asking questions below. My aim is to make it more of a Go-like app than my own invention with bad practises. Just a side note, I've cut things sorter to keep the post short but if you want to see full picture this is the GitHub page.
Is the way I am bootstraping the app correct? The
main.goprepares things and passes toapi.gowho starts the server somain.gois responsible for bootstraping things andapi.gostarts things.The
config.gohas global vars but I am not directly accessing them in where they are needed. Instead, I am injecting them to functions that depend on them. Am I currently over engineering it or is it ok?Shall I create/bootstrap
http.handlerwithNew()inmain.goand inject intoapp.goas I do for the config? Or is it fine to keep it as is just because bothserver.goandhandler.gofiles are under same directory?
.
├── bin
│ └── api
├── cmd
│ └── api
│ └── main.go
└── internal
├── app
│ └── api.go
├── config
│ └── config.go
├── controller
│ └── index
└── http
├── handler.go
└── server.go
cmd/api/main.go
# This is also boots logger but removed to keep it short for now
package main
import (
"github.com/myself/api/internal/app"
"github.com/myself/api/internal/config"
)
func main() {
config.Load()
app.Run(config.Srv.Address)
}
internal/config/config.go
# This has more stuff in it
package config
import "sync"
var (
App application
Srv server
o sync.Once
)
type application struct {
Env string
}
type server struct {
Address string
}
func Load() {
o.Do(func() {
App = application{Env:"dev"}
Srv = server{Address:"0.0.0.0:8080"}
})
}
internal/app/api.go
# This is as simple as this
package app
import "github.com/myself/api/internal/http"
func Run(addr string) {
http.Start(addr)
}
internal/http/server.go
# This actually handles signals and shutdown
package http
import (
"log"
"net/http"
)
func Start(addr string) {
if err := http.ListenAndServe(addr, handler()); err != nil {
log.Fatalf("couldn't start http server")
}
}
internal/http/handler.go
# This has little bit stuff in it
package http
import (
"github.com/myself/api/internal/controller/index"
"github.com/julienschmidt/httprouter"
)
func handler() *httprouter.Router {
rtr := httprouter.New()
rtr.GET("/", index.Index)
return rtr
}
internal/controller/index/index.go
package index
import (
"github.com/julienschmidt/httprouter"
"net/http"
)
func Index(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
}