Skip to content

Commit 2e37034

Browse files
committed
Improved refactoring.
1 parent 78b1bb5 commit 2e37034

20 files changed

+290
-202
lines changed

cmd/apiserver/main.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,13 @@ func init() {
1818
func main() {
1919
flag.Parse()
2020

21-
2221
config := apiserver.NewConfig()
2322
_, err := toml.DecodeFile(configPath, config)
2423
if err != nil {
2524
log.Fatal(err)
2625
}
2726

28-
s := apiserver.New(config)
29-
if err := s.Start(); err != nil {
27+
if err := apiserver.Start(config); err != nil {
3028
log.Fatal(err)
3129
}
3230
}

configs/apiserver.toml

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
bind_addr = ":8080"
22
log_level = "debug"
3-
4-
[store]
53
database_url = "postgres://postgres:211217ns@localhost/restapi_dev?sslmode=disable"

interanal/app/apiserver/apiserver.go

+16-62
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,35 @@
11
package apiserver
22

33
import (
4-
"github.com/dannycrief/go-http-rest-api/interanal/app/store"
5-
"github.com/gorilla/mux"
6-
"github.com/sirupsen/logrus"
7-
"io"
4+
"database/sql"
5+
"github.com/dannycrief/go-http-rest-api/interanal/app/store/sqlstore"
86
"net/http"
97
)
108

11-
//APIServer ...
12-
type APIServer struct {
13-
config *Config
14-
logger *logrus.Logger
15-
router *mux.Router
16-
store *store.Store
17-
}
18-
19-
//New ...
20-
func New(config *Config) *APIServer {
21-
return &APIServer{
22-
config: config,
23-
logger: logrus.New(),
24-
router: mux.NewRouter(),
25-
}
26-
}
27-
289
//Start ...
29-
func (s *APIServer) Start() error {
30-
if err := s.configureLogger(); err != nil {
31-
return err
10+
func Start(config *Config) error {
11+
db, err := newDB(config.DatabaseURL)
12+
if err != nil {
13+
return nil
3214
}
3315

34-
s.configureRouter()
35-
36-
if err := s.configureStore(); err != nil {
37-
return err
38-
}
16+
defer db.Close()
3917

40-
s.logger.Info("starting api server")
18+
store := sqlstore.New(db)
19+
s := newServer(store)
4120

42-
return http.ListenAndServe(s.config.BindAddr, s.router)
21+
return http.ListenAndServe(config.BindAddr, s)
4322
}
4423

45-
//configureLogger...
46-
func (s *APIServer) configureLogger() error {
47-
level, err := logrus.ParseLevel(s.config.LogLevel)
24+
func newDB(databaseURL string) (*sql.DB, error) {
25+
db, err := sql.Open("postgres", databaseURL)
4826
if err != nil {
49-
return err
50-
}
51-
52-
s.logger.SetLevel(level)
53-
54-
return nil
55-
}
56-
//configureRouter ...
57-
func (s *APIServer) configureRouter() {
58-
s.router.HandleFunc("/hello", s.handleHello())
59-
}
60-
61-
func (s *APIServer) configureStore() error {
62-
st := store.New(s.config.Store)
63-
if err := st.Open(); err != nil {
64-
return err
27+
return nil, err
6528
}
6629

67-
s.store = st
68-
return nil
69-
}
70-
71-
//handleHello ...
72-
func (s *APIServer) handleHello() http.HandlerFunc {
73-
type request struct {
74-
name string
30+
if err := db.Ping(); err != nil {
31+
return nil, err
7532
}
7633

77-
return func(w http.ResponseWriter, r *http.Request) {
78-
io.WriteString(w, "Hello")
79-
}
34+
return db, nil
8035
}
81-

interanal/app/apiserver/apiserver_internal_test.go

-16
This file was deleted.

interanal/app/apiserver/config.go

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
package apiserver
22

3-
import (
4-
"github.com/dannycrief/go-http-rest-api/interanal/app/store"
5-
)
6-
73
//Config ...
84
type Config struct {
9-
BindAddr string `toml:"bind_addr"`
10-
LogLevel string `toml:"log_level"`
11-
Store *store.Config
5+
BindAddr string `toml:"bind_addr"`
6+
LogLevel string `toml:"log_level"`
7+
DatabaseURL string `toml:"database_url"`
128
}
139

1410
//NewConfig ...
1511
func NewConfig() *Config {
1612
return &Config{
1713
BindAddr: ":8080",
1814
LogLevel: "debug",
19-
Store: store.NewConfig(),
2015
}
2116

2217
}

interanal/app/apiserver/server.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package apiserver
2+
3+
import (
4+
"github.com/dannycrief/go-http-rest-api/interanal/app/store"
5+
"github.com/gorilla/mux"
6+
"github.com/sirupsen/logrus"
7+
"net/http"
8+
)
9+
10+
type server struct {
11+
router *mux.Router
12+
logger *logrus.Logger
13+
store store.Store
14+
}
15+
16+
func newServer(store store.Store) *server {
17+
s := &server{
18+
router: mux.NewRouter(),
19+
logger: logrus.New(),
20+
store: store,
21+
}
22+
23+
s.configureRouter()
24+
25+
return s
26+
}
27+
28+
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
29+
s.router.ServeHTTP(w, r)
30+
31+
}
32+
33+
func (s *server) configureRouter() {
34+
s.router.HandleFunc("/users", s.handleUsersCreate()).Methods("POST")
35+
}
36+
37+
func (s *server) handleUsersCreate() http.HandlerFunc {
38+
return func(w http.ResponseWriter, r *http.Request) {
39+
40+
}
41+
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package apiserver
2+
3+
import (
4+
"github.com/dannycrief/go-http-rest-api/interanal/app/store/teststore"
5+
"github.com/stretchr/testify/assert"
6+
"net/http"
7+
"net/http/httptest"
8+
"testing"
9+
)
10+
11+
func TestServer_HandleUserCreate(t *testing.T) {
12+
rec := httptest.NewRecorder()
13+
req, _ := http.NewRequest(http.MethodPost, "/users", nil)
14+
s := newServer(teststore.New())
15+
s.ServeHTTP(rec, req)
16+
assert.Equal(t, rec.Code, http.StatusOK)
17+
}

interanal/app/store/config.go

-11
This file was deleted.

interanal/app/store/errors.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package store
2+
3+
import "errors"
4+
5+
var (
6+
//ErrRecordNotFound ...
7+
ErrRecordNotFound = errors.New("record not found")
8+
)

interanal/app/store/repository.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package store
2+
3+
import "github.com/dannycrief/go-http-rest-api/interanal/app/model"
4+
5+
//UserRepository ...
6+
type UserRepository interface {
7+
Create(*model.User) error
8+
FindByEmail(string) (*model.User, error)
9+
}

interanal/app/store/sqlstore/store.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package sqlstore
2+
3+
import (
4+
"database/sql"
5+
"github.com/dannycrief/go-http-rest-api/interanal/app/store"
6+
7+
_ "github.com/lib/pq" // ...
8+
)
9+
10+
//Store ...
11+
type Store struct {
12+
db *sql.DB
13+
userRepository *UserRepository
14+
}
15+
16+
//New ...
17+
func New(db *sql.DB) *Store {
18+
return &Store{
19+
db: db,
20+
}
21+
}
22+
23+
24+
25+
//User ...
26+
func (s *Store) User() store.UserRepository {
27+
if s.userRepository != nil {
28+
return s.userRepository
29+
}
30+
31+
s.userRepository = &UserRepository{
32+
store: s,
33+
}
34+
35+
return s.userRepository
36+
}

interanal/app/store/store_test.go interanal/app/store/sqlstore/store_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package store_test
1+
package sqlstore_test
22

33
import (
44
"os"
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package sqlstore
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"strings"
7+
"testing"
8+
)
9+
10+
//TestDB ...
11+
func TestDB(t *testing.T, databaseURL string) (*sql.DB, func(...string)) {
12+
t.Helper()
13+
14+
db, err := sql.Open("postgres", databaseURL)
15+
if err != nil {
16+
t.Fatal(err)
17+
}
18+
19+
if err := db.Ping(); err != nil {
20+
t.Fatal(err)
21+
}
22+
23+
return db, func(tables ...string) {
24+
if len(tables) > 0 {
25+
db.Exec(fmt.Sprintf("TRUNCATE %s CASCADE", strings.Join(tables, ", ")))
26+
}
27+
28+
db.Close()
29+
}
30+
}

interanal/app/store/userrepository.go interanal/app/store/sqlstore/userrepository.go

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
package store
1+
package sqlstore
22

3-
import "github.com/dannycrief/go-http-rest-api/interanal/app/model"
3+
import (
4+
"database/sql"
5+
"github.com/dannycrief/go-http-rest-api/interanal/app/model"
6+
"github.com/dannycrief/go-http-rest-api/interanal/app/store"
7+
)
48

59
//UserRepository ...
610
type UserRepository struct {
711
store *Store
812
}
913

1014
//Create ...
11-
func (r *UserRepository) Create(u *model.User) (*model.User, error) {
15+
func (r *UserRepository) Create(u *model.User) error {
1216
if err := u.Validate(); err != nil {
13-
return nil, err
17+
return err
1418
}
1519
if err := u.BeforeCreate(); err != nil {
16-
return nil, err
20+
return err
1721
}
1822

19-
if err := r.store.db.QueryRow(
23+
return r.store.db.QueryRow(
2024
"insert into users (email, encrypted_password) values ($1, $2) returning id",
2125
u.Email, u.EncryptedPassword,
22-
).Scan(&u.ID); err != nil {
23-
return nil, err
24-
}
25-
26-
return u, nil
26+
).Scan(&u.ID)
2727
}
2828

2929
//FindByEmail ...
@@ -37,6 +37,9 @@ func (r *UserRepository) FindByEmail(email string) (*model.User, error) {
3737
&u.Email,
3838
&u.EncryptedPassword,
3939
); err != nil {
40+
if err == sql.ErrNoRows {
41+
return nil, store.ErrRecordNotFound
42+
}
4043
return nil, err
4144
}
4245
return u, nil

0 commit comments

Comments
 (0)