diff --git a/allsrv/server.go b/allsrv/server.go index 579e1e9..1fcac59 100644 --- a/allsrv/server.go +++ b/allsrv/server.go @@ -34,7 +34,7 @@ import ( a) there is nothing actionable, so how does the consumer know to handle the error? b) if the APIs evolve, how does the consumer distinguish between old and new? 10) Observability.... - 11) hard coding UUID generation into db + ✅11) hard coding UUID generation into db 12) possible race conditions in inmem store Praises: @@ -48,14 +48,31 @@ type Server struct { db *InmemDB // 1) user, pass string // 3) + + idFn func() string // 11) +} + +// WithIDFn sets the id generation fn for the server. +func WithIDFn(fn func() string) func(*Server) { + return func(s *Server) { + s.idFn = fn + } } -func NewServer(db *InmemDB, user, pass string) *Server { +func NewServer(db *InmemDB, user, pass string, opts ...func(*Server)) *Server { s := Server{ db: db, user: user, pass: pass, + idFn: func() string { + // defaults to using a uuid + return uuid.Must(uuid.NewV4()).String() + }, } + for _, o := range opts { + o(&s) + } + s.routes() return &s } @@ -93,15 +110,10 @@ func (s *Server) createFoo(w http.ResponseWriter, r *http.Request) { return } - newFooID, err := s.db.createFoo(f) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) // 9) - return - } + f.ID = s.idFn() // 11) - f, err = s.db.readFoo(newFooID) - if err != nil { - w.WriteHeader(http.StatusNotFound) // 9) + if err := s.db.createFoo(f); err != nil { + w.WriteHeader(http.StatusInternalServerError) // 9) return } @@ -166,18 +178,16 @@ type InmemDB struct { m []Foo // 12) } -func (db *InmemDB) createFoo(f Foo) (string, error) { - f.ID = uuid.Must(uuid.NewV4()).String() // 11) - +func (db *InmemDB) createFoo(f Foo) error { for _, existing := range db.m { if f.Name == existing.Name { - return "", errors.New("foo " + f.Name + " exists") // 8) + return errors.New("foo " + f.Name + " exists") // 8) } } db.m = append(db.m, f) - return f.ID, nil + return nil } func (db *InmemDB) readFoo(id string) (Foo, error) { diff --git a/allsrv/server_test.go b/allsrv/server_test.go index c87201f..5a21754 100644 --- a/allsrv/server_test.go +++ b/allsrv/server_test.go @@ -18,7 +18,9 @@ func TestServer(t *testing.T) { t.Run("foo create", func(t *testing.T) { t.Run("when provided a valid foo should pass", func(t *testing.T) { db := new(allsrv.InmemDB) - svr := allsrv.NewServer(db, "dodgers@stink.com", "PaSsWoRd") + svr := allsrv.NewServer(db, "dodgers@stink.com", "PaSsWoRd", allsrv.WithIDFn(func() string { + return "id1" + })) req := httptest.NewRequest("POST", "/foo", newJSONBody(t, allsrv.Foo{ Name: "first-foo", @@ -31,11 +33,8 @@ func TestServer(t *testing.T) { assert.Equal(t, http.StatusCreated, rec.Code) expectJSONBody(t, rec.Body, func(t *testing.T, got allsrv.Foo) { - assert.NotZero(t, got.ID) - got.ID = "" // this hurts :-( - want := allsrv.Foo{ - ID: "", // ruh ohhh + ID: "id1", Name: "first-foo", Note: "some note", }