Golang Application Structure and Development
bin/
(Generated) The build output of the application
cmd/
The commands avaliable for running the application
handler/
The handlers for the requests
route/
The route configuration for handlers
db/
repo/
The Data Access Layer (DAL) for the database
sql/
SQL files for Repo
sql.go
The generated Go file for the files in the SQL sub-directory
migration/
sql/
sql.go
The generated Go file for the files in the SQL sub-directory
seed/
sql/
sql.go
The generated Go file for the files in the SQL sub-directory
service/
Services for interacting with multiple sub-layers at once
worker/
Background job executors
mail/
Email templates
web/
Web UI
pkg/
Common utility packages for various parts of the application
public/
(Generated) The output of building the React app
vendor/
(Generated) The vendor packages for the application
.editorconfig
The editor configuration file defining how files should be laid out
.gitlab-ci.yml
The Gitlab CI configuration
LICENSE
The license for the project
README.md
The main README document
Dockerfile
The Docker image build file
Makefile
The set of commands avaliable for running, building, and setting up working project
type ProjectRepo interface {
GetNames (uint64 , uint64 ) []string
}
type Project struct {
DB * sqlx.DB
}
func (p Project ) GetNames (id , userID uint64 ) []string {
return p .DB .Get ("SELECT name FROM projects WHERE id = $1 AND user_id = $2" , id , userID )
}
type ProjectService interface {
GetNames (uint64 , uint64 ) []string
}
type Project struct {
ProjectRepo repo.ProjectRepo
}
func (p Project ) GetNames (id , userID uint64 ) []string {
return p .GetNames (id , userID )
}
type Project struct {
ProjectService service.Project
}
func (p Project ) GetNames () http.Handler {
return func (w http.ResponseWriter , r * http.Request , ps httprouter.Params ) {
var (
id = ps .Get ("id" )
userID = r .URL .Query ().Get ("userId" )
)
if id == 0 || userID == 0 {
http .Error (w , "ID and User ID are both required" )
return
}
names := p .ProjectService .GetNames (id , userID )
json .NewEncoder (w ).Encode (names )
}
}
func (p Project ) GetManyNames () http.Handler {
type request struct {
IDs []uint64 `json:"ids"`
UserID uint64 `json:"userId"`
}
return func (w http.ResponseWriter , r * http.Request , ps httprouter.Params ) {
var req request
json .NewDecoder (r .Body ).Decode (req )
respChan = make (chan []string )
for _ , id := range req .IDs {
go func () { respChan <- p .ProjectService .GetNames (id , req .UserID ) }()
}
var res []string
for i := 0 ; i < len (req .IDs ); i ++ {
select {
case names <- respChan :
res = append (res , names )
}
}
json .NewEncoder (w ).Encode (res )
}
}
func Project (r httprouter.Router , h handler.Project ) {
r .GET ("/projects/:id/names" , h .GetNames ())
}
const (
databaseURL = "postgres://postgres:postgres@localhost:5433/test_db"
addr = ":3000"
publicDir = "public"
)
func serveStatic (r httprouter.Router , dir string ) {
// if public directory exists
// serve static files from public
// else
// log warning that static files not set up
}
func main () {
// Connect to Resources
db , err := sqlx .Dial (databaseURL )
if err != nil {
log .Fatal (err )
}
// Create Repos
projectRepo := & repo.Project {DB : db }
// Create Services
projectService := & service.Project {ProjectRepo : projectRepo }
// Create Handlers
projectHandler := & handler.Project {ProjectService : projectService }
// Create the router
router := httprouter .New ()
// Add Routes
route .Project (router , projectHandler )
// Serve Static
serveStatic (router , publicDir )
// Start the Server
log .Fatal (http .ListenAndServe (addr , router ))
}