Skip to content

Commit 948b3f7

Browse files
authored
Inject DB and Logger
This PR creates an Env struct which contains DB (*sql.DB) and Logger (*zap.SugaredLogger) which enables handler dependency injection via closures. Handler functions moved out of `./pkg/cmd/cmd.go` and to a new directory, `./pkg/handlers/`. Handler functions use a closure to make Env available to the handler, injecting the DB and Logger dependencies into the handler. This is an implementation of dep injection option #2b as seen [here](https://www.alexedwards.net/blog/organising-database-access#closure). Option 3 is also something to consider, but for now this is functional and moves DB and Logger out of the global scope. A few housekeeping items are addressed as well: updating README.md and .gitignore.
2 parents 8c73a21 + cf019ef commit 948b3f7

File tree

9 files changed

+93
-64
lines changed

9 files changed

+93
-64
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
.env*
2+
3+
# VSCODE
24
.vscode
5+
__debug_*
36

47
# Binaries for programs and plugins
58
*.exe
@@ -12,4 +15,4 @@
1215
*.test
1316

1417
# Output of the go coverage tool, specifically when used with LiteIDE
15-
*.out
18+
*.out

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,13 @@ $ go run cmd/main.go
5858

5959
## Environment Variables
6060

61+
### DB_DRIVER Options
62+
63+
* mysql
64+
* pgx
65+
6166
```
62-
DB_DRIVER=mysql # postgres
67+
DB_DRIVER=mysql # pgx
6368
DB_HOST=127.0.0.1
6469
DB_PORT=32084
6570
DB_USER=root

cmd/gabi/main.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"database/sql"
54
"log"
65

76
"go.uber.org/zap"
@@ -10,19 +9,15 @@ import (
109
"github.com/app-sre/gabi/pkg/cmd"
1110
)
1211

13-
var DB *sql.DB // Replace with dependency injection for logger and db pool
14-
1512
func main() {
1613
logger, err := zap.NewDevelopment() // NewProduction
1714
if err != nil {
1815
log.Fatalf("can't initialize zap logger: %v", err)
1916
}
2017
defer logger.Sync()
2118

22-
undo := zap.ReplaceGlobals(logger)
23-
defer undo()
24-
25-
zap.S().Info("Starting gabi server version " + gabi.Version)
19+
loggerS := logger.Sugar()
20+
loggerS.Info("Starting gabi server version " + gabi.Version)
2621

27-
cmd.Run()
22+
cmd.Run(loggerS)
2823
}

env.template

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
DB_DRIVER=postgres
2-
DB_HOST=localhost
3-
DB_PORT=3306
1+
DB_DRIVER=pgx
2+
DB_HOST=127.0.0.1
3+
DB_PORT=5432
44
DB_USER=postgres
55
DB_PASS=postgres
66
DB_NAME=mydb
7-
DB_WRITE=false
7+
DB_WRITE=false

pkg/cmd/cmd.go

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,55 @@
11
package cmd
22

33
import (
4-
"context"
54
"database/sql"
65
"log"
76
"net/http"
87
"strconv"
9-
"time"
108

11-
"github.com/etherlabsio/healthcheck/v2"
129
_ "github.com/go-sql-driver/mysql"
13-
"github.com/gorilla/handlers"
10+
gorillaHandlers "github.com/gorilla/handlers"
1411
"github.com/gorilla/mux"
1512
_ "github.com/jackc/pgx/v4/stdlib"
1613
"go.uber.org/zap"
1714

15+
gabi "github.com/app-sre/gabi/pkg"
1816
"github.com/app-sre/gabi/pkg/env/db"
19-
"github.com/app-sre/gabi/pkg/query"
17+
"github.com/app-sre/gabi/pkg/handlers"
2018
)
2119

22-
func Run() {
20+
func Run(logger *zap.SugaredLogger) {
2321
dbe := db.Dbenv{}
2422
err := dbe.Populate()
2523
if err != nil {
26-
log.Fatal(err)
24+
logger.Fatal(err)
2725
}
28-
zap.S().Info("Database environment variables populated.")
2926

30-
DB, err := sql.Open(dbe.DB_DRIVER, dbe.ConnStr)
27+
logger.Info("Database environment variables populated.")
28+
29+
db, err := sql.Open(dbe.DB_DRIVER, dbe.ConnStr)
3130
if err != nil {
32-
log.Fatal("Fatal error opening database.")
31+
logger.Fatal("Fatal error opening database.")
3332
}
34-
defer DB.Close()
35-
zap.S().Info("Database connection handle established.")
36-
zap.S().Infof("Using %s database driver.", dbe.DB_DRIVER)
33+
defer db.Close()
34+
35+
env := &gabi.Env{DB: db, Logger: logger}
36+
logger.Info("Database connection handle established.")
37+
logger.Infof("Using %s database driver.", dbe.DB_DRIVER)
3738

3839
r := mux.NewRouter()
3940

40-
r.Handle("/healthcheck", healthcheck.Handler(
41-
healthcheck.WithTimeout(5*time.Second),
42-
healthcheck.WithChecker(
43-
"database", healthcheck.CheckerFunc(
44-
func(ctx context.Context) error {
45-
return DB.PingContext(ctx)
46-
},
47-
),
48-
),
49-
))
41+
r.Handle("/healthcheck", handlers.Healthcheck(env))
42+
r.HandleFunc("/query", handlers.Query(env))
5043

51-
r.HandleFunc("/query", query.Handler)
52-
zap.S().Info("Router initialized.")
44+
logger.Info("Router initialized.")
5345

5446
servePort := 8080
55-
zap.S().Infof("HTTP server starting on port %d.", servePort)
47+
logger.Infof("HTTP server starting on port %d.", servePort)
5648

5749
// Temp workaround for easy to access io.Writer
5850
httpLogger := log.Default()
5951
http.ListenAndServe(
6052
":"+strconv.Itoa(servePort),
61-
handlers.LoggingHandler(httpLogger.Writer(), r),
53+
gorillaHandlers.LoggingHandler(httpLogger.Writer(), r),
6254
)
6355
}

pkg/gabi.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
11
package gabi
22

3+
import (
4+
"database/sql"
5+
6+
"go.uber.org/zap"
7+
)
8+
39
const Version = "0.0.1"
10+
11+
type Env struct {
12+
DB *sql.DB
13+
Logger *zap.SugaredLogger
14+
}

pkg/handlers/healthcheck.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package handlers
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"time"
7+
8+
"github.com/etherlabsio/healthcheck/v2"
9+
10+
gabi "github.com/app-sre/gabi/pkg"
11+
)
12+
13+
func Healthcheck(env *gabi.Env) http.Handler {
14+
return healthcheck.Handler(
15+
healthcheck.WithTimeout(5*time.Second),
16+
healthcheck.WithChecker(
17+
"database", healthcheck.CheckerFunc(
18+
func(ctx context.Context) error {
19+
return env.DB.PingContext(ctx)
20+
},
21+
),
22+
),
23+
)
24+
}

pkg/handlers/query.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package handlers
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
7+
gabi "github.com/app-sre/gabi/pkg"
8+
)
9+
10+
func Query(env *gabi.Env) http.HandlerFunc {
11+
return func(w http.ResponseWriter, r *http.Request) {
12+
// https://stackoverflow.com/a/46021789
13+
env.Logger.Info("testing")
14+
fmt.Fprintf(w, "%s %s %s \n", r.Method, r.URL, r.Proto)
15+
for k, v := range r.Header {
16+
fmt.Fprintf(w, "Header field %q, Value %q\n", k, v)
17+
env.Logger.Infof("Header field %q, Value %q", k, v)
18+
}
19+
fmt.Fprintf(w, "Host = %q\n", r.Host)
20+
fmt.Fprintf(w, "RemoteAddr= %q\n", r.RemoteAddr)
21+
}
22+
}

pkg/query/handler.go

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)