]> localhost Git - tq-wave11-pf.git/commitdiff
feat: code format + update + a bunch of utils
authorJansen <[email protected]>
Thu, 7 Aug 2025 19:50:25 +0000 (15:50 -0400)
committerJansen <[email protected]>
Thu, 7 Aug 2025 19:50:25 +0000 (15:50 -0400)
13 files changed:
internal/errors/errors.go [new file with mode: 0644]
persistence/inmemory/ingredients.go
persistence/inmemory/inmemory.go
persistence/persistence.go
pkg/core/ingrendient.go
pkg/http/errors.go [deleted file]
pkg/http/http.go
pkg/http/ingredient.go
pkg/http/util/errors.go [new file with mode: 0644]
pkg/http/util/middlewares.go [moved from pkg/http/middlewares.go with 88% similarity]
pkg/http/util/parsers.go [new file with mode: 0644]
pkg/services/errors.go [deleted file]
pkg/services/ingredient.go

diff --git a/internal/errors/errors.go b/internal/errors/errors.go
new file mode 100644 (file)
index 0000000..957d0c4
--- /dev/null
@@ -0,0 +1,53 @@
+package errors
+
+import "fmt"
+
+type ErrorCode int
+
+const (
+       DefaultError ErrorCode = iota
+       BadInputError
+       ConflictError
+       NotFoundError
+       BadIdError
+)
+
+func (c ErrorCode) MapToHTTP() int {
+       switch c {
+       case BadIdError:
+               fallthrough
+       case BadInputError:
+               return 400
+
+       case ConflictError:
+               return 409
+
+       case NotFoundError:
+               return 404
+
+       default:
+               return 500
+       }
+}
+
+type Error struct {
+       Code    ErrorCode
+       Message string
+}
+
+func (e Error) Error() string {
+       return fmt.Sprintf("(%d)%s", e.Code, e.Message)
+}
+
+func MapError(err error) Error {
+       switch err.Error() {
+       case "bad_id":
+               return Error{Code: BadIdError, Message: err.Error()}
+       case "name_in_use":
+               return Error{Code: ConflictError, Message: err.Error()}
+       case "not_found":
+               return Error{Code: NotFoundError, Message: err.Error()}
+       default:
+               return Error{Code: DefaultError, Message: "Something bad happened"}
+       }
+}
index a37622a898fc0fab7487e8be08c2d315134775cb..6cb91c9c128d85317b362cf2f75714b1f078e9b9 100644 (file)
@@ -17,19 +17,39 @@ func (p *InmemoryPersistence) IngredientCreate(in core.Ingredient) (core.Ingredi
                return core.Ingredient{}, errors.New("name_in_use")
        }
 
-
        id := len(p.ingredients) + 1
 
        createdAt := time.Now()
 
        in.Id = id
        in.CreatedAt = &createdAt
-       p.ingredients   = append(p.ingredients, in)
+       p.ingredients = append(p.ingredients, in)
 
        return in, nil
 }
 
 func (p *InmemoryPersistence) IngredientUpdate(in core.Ingredient) error {
+       ingredient, err := p.IngredientGet(in.Id)
+       if err != nil {
+               return err
+       }
+       if ingredient == nil {
+               return errors.New("not_found")
+       }
+
+       // IRW this would be an index, so np leaving it here
+       found, err := p.IngredientGetByName(in.Name)
+       if err != nil {
+               return err
+       }
+       if found != nil && found.Id != in.Id {
+               return errors.New("name_in_use")
+       }
+
+       ingredient.Name = in.Name
+       ingredient.Quantity = in.Quantity
+       ingredient.Description = in.Description
+
        return nil
 }
 
@@ -38,7 +58,7 @@ func (p *InmemoryPersistence) IngredientDeactivate(id int) error {
 }
 
 func (p *InmemoryPersistence) IngredientGet(id int) (*core.Ingredient, error) {
-       if id < 0 || id > len(p.ingredients) {
+       if id < 1 || id > len(p.ingredients) {
                return nil, nil
        }
        return &p.ingredients[id-1], nil
index b4245feabb17315318a6ee758e34c766e14d3bef..831c6d12513fe8e74d9a2d9dfae476dbe4c2bbb3 100644 (file)
@@ -13,4 +13,3 @@ func NewPersistence() InmemoryPersistence {
                ingredients: []core.Ingredient{},
        }
 }
-
index 700aac446bff92c8a292d8d143067aa72bd5ba90..8fe6d8496555c53e2b2ac3e802fc4ea733fb430c 100644 (file)
@@ -3,4 +3,3 @@ package persistence
 type Persistence interface {
        IngredientRepository
 }
-
index 000cf3134b3ea6f36e09f17e6a30fb3e8bb19791..26dc172892ecb7cd83572b9d016e31a0068edea0 100644 (file)
@@ -1,12 +1,33 @@
 package core
 
-import "time"
+import (
+       "time"
+
+       "jsdaj.tq/pf/internal/errors"
+)
 
 type Ingredient struct {
-       Id          int    `json:"id,omitempty"`
-       Name        string `json:"name"`
-       Quantity    int    `json:"quantity"`
-       Description string `json:"description"`
+       Id          int        `json:"id,omitempty"`
+       Name        string     `json:"name"`
+       Quantity    int        `json:"quantity"`
+       Description string     `json:"description"`
        CreatedAt   *time.Time `json:"createdAt,omitempty"`
 }
 
+func (ingredient Ingredient) IsValid() error {
+       isMissingRequiredFields := ingredient.Name == "" || ingredient.Quantity == 0
+       isBadName := len(ingredient.Name) < 3
+       isBadQuantity := ingredient.Quantity < 0
+
+       if isMissingRequiredFields {
+               return errors.Error{Code: errors.BadInputError, Message: "fields required: name, quantity"}
+       }
+       if isBadName {
+               return errors.Error{Code: errors.BadInputError, Message: "name should be have more than 2 chars"}
+       }
+       if isBadQuantity {
+               return errors.Error{Code: errors.BadInputError, Message: "quantity should be positive"}
+       }
+
+       return nil
+}
diff --git a/pkg/http/errors.go b/pkg/http/errors.go
deleted file mode 100644 (file)
index 6cb51eb..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-package http
-
-import (
-       "encoding/json"
-       "log"
-       shttp "net/http"
-
-       "jsdaj.tq/pf/pkg/services"
-)
-
-type httpError struct {
-       Status int               `json:"status"`
-       Message string `json:"message"`
-}
-
-func handleError(w shttp.ResponseWriter, status int, message string) {
-       response := httpError{
-               Status: status,
-               Message: message,
-       }
-
-       body, err := json.Marshal(response)
-       if err != nil {
-               body = []byte("Something went wrong")
-       }
-
-       w.WriteHeader(status)
-       w.Write(body)
-}
-
-func handleErrorByCode(w shttp.ResponseWriter, status int) {
-       switch status {
-       case shttp.StatusBadRequest:
-               handleError(w, status, "Bad body")
-       default:
-               handleError(w, shttp.StatusInternalServerError, "Something went wrong")
-       }
-}
-
-func handleServiceError(w shttp.ResponseWriter, err error) {
-       switch err.(type) {
-       case services.Error:
-               e := err.(services.Error)
-               status := e.Code.MapToHTTP()
-               handleError(w, status, e.Message)
-       default:
-               log.Printf("error: Expecting 'services.Error', received: %s\n", err)
-               handleErrorByCode(w, shttp.StatusInternalServerError)
-       }
-}
index b6146282dabc877e2663a223e77b206ee0e34471..f4ad4d0976d66ad8df0c0437c7216852fcf8b6c6 100644 (file)
@@ -6,6 +6,7 @@ import (
        shttp "net/http"
 
        "jsdaj.tq/pf/persistence"
+       "jsdaj.tq/pf/pkg/http/util"
        "jsdaj.tq/pf/pkg/services"
 )
 
@@ -21,7 +22,7 @@ type Server struct {
 func (s *Server) Start() {
        s.initRoutes()
 
-       s.serv.Handler = middlewares(s.mux)
+       s.serv.Handler = util.Middlewares(s.mux)
 
        log.Printf(">> Starting server at :%d\n", s.port)
        s.serv.ListenAndServe()
@@ -45,8 +46,12 @@ func InitServer(port int, persist persistence.Persistence) Server {
 func (s *Server) initRoutes() {
        s.mux = shttp.NewServeMux()
 
-       s.mux.Handle("/ingredient", s.ingredientHandler())
+       s.mux.HandleFunc("POST /ingredient", s.ingredientHandleCreate)
+       s.mux.HandleFunc("PUT /ingredient/{id}", s.ingredientHandleUpdate)
+       s.mux.HandleFunc("DELETE /ingredient/{id}", s.ingredientHandleDelete)
+       s.mux.HandleFunc("GET /ingredient/{id}", s.ingredientHandleGet)
+       s.mux.HandleFunc("GET /ingredient", s.ingredientHandleList)
+
        s.mux.Handle("/dish", dishHandler())
        s.mux.Handle("/menu", menuHandler())
 }
-
index c35ef8d223b61da618126a280578d695e06c2b4e..671f486f88606024346cd6dd1894d3fc5ae72cbc 100644 (file)
@@ -1,69 +1,67 @@
 package http
 
 import (
-       "encoding/json"
-       "log"
+       serrors "errors"
        shttp "net/http"
+       "strconv"
 
+       "jsdaj.tq/pf/internal/errors"
        "jsdaj.tq/pf/pkg/core"
+       "jsdaj.tq/pf/pkg/http/util"
 )
 
 func (s *Server) ingredientHandleCreate(w shttp.ResponseWriter, r *shttp.Request) {
        var input core.Ingredient
 
-       err := json.NewDecoder(r.Body).Decode(&input)
+       err := util.ParseRequestAndErr(w, r, &input)
        if err != nil {
-               log.Printf("!! %s\n", err)
-               handleErrorByCode(w, shttp.StatusBadRequest)
                return
        }
 
        ingredient, err := s.ingredients.Create(input)
        if err != nil {
-               handleServiceError(w, err)
+               util.HandleServiceError(w, err)
                return
        }
 
-       response, err := json.Marshal(ingredient)
+       util.ParseAndWriteResponse(w, ingredient, shttp.StatusCreated)
+}
+
+func (s *Server) ingredientHandleUpdate(w shttp.ResponseWriter, r *shttp.Request) {
+       id, err := strconv.Atoi(r.PathValue("id"))
        if err != nil {
-               handleErrorByCode(w, shttp.StatusInternalServerError)
+               util.HandleServiceError(w, errors.MapError(serrors.New("bad_id")))
                return
        }
-       
-       w.WriteHeader(shttp.StatusCreated)
-       w.Write(response)
-}
-
-func (s *Server) ingredientHandleUpdate(w shttp.ResponseWriter, r *shttp.Request) {}
-
-func (s *Server) ingredientHandleDelete(w shttp.ResponseWriter, r *shttp.Request) {}
 
-func (s *Server) ingredientHandleGet(w shttp.ResponseWriter, r *shttp.Request) {}
+       var ingredient core.Ingredient
 
-func (s *Server) ingredientHandleList(w shttp.ResponseWriter, r *shttp.Request) {
-       ingredients, err := s.ingredients.List()
+       err = util.ParseRequestAndErr(w, r, &ingredient)
        if err != nil {
-               handleError(w, shttp.StatusInternalServerError, err.Error())
                return
        }
 
-       response, err := json.Marshal(ingredients)
+       ingredient.Id = id
+
+       err = s.ingredients.Update(ingredient)
        if err != nil {
-               handleErrorByCode(w, shttp.StatusInternalServerError)
+               util.HandleServiceError(w, err)
                return
        }
-       
-       w.Write(response)
+
+       util.ParseAndWriteResponse(w, ingredient, shttp.StatusOK)
 }
 
-func (s *Server) ingredientHandler() shttp.Handler {
-       mux := shttp.NewServeMux()
+func (s *Server) ingredientHandleDelete(w shttp.ResponseWriter, r *shttp.Request) {}
 
-       mux.HandleFunc("POST /ingredient", s.ingredientHandleCreate)
-       mux.HandleFunc("PUT /ingredient/{id}", s.ingredientHandleUpdate)
-       mux.HandleFunc("DELETE /ingredient/{id}", s.ingredientHandleDelete)
-       mux.HandleFunc("GET /ingredient/{id}", s.ingredientHandleGet)
-       mux.HandleFunc("GET /ingredient", s.ingredientHandleList)
+func (s *Server) ingredientHandleGet(w shttp.ResponseWriter, r *shttp.Request) {}
+
+func (s *Server) ingredientHandleList(w shttp.ResponseWriter, r *shttp.Request) {
+       ingredients, err := s.ingredients.List()
+       if err != nil {
+               util.HandleError(w, shttp.StatusInternalServerError, err.Error())
+               return
+       }
 
-       return mux
+       util.ParseAndWriteResponse(w, ingredients, shttp.StatusOK)
 }
diff --git a/pkg/http/util/errors.go b/pkg/http/util/errors.go
new file mode 100644 (file)
index 0000000..0d0357f
--- /dev/null
@@ -0,0 +1,49 @@
+package util
+
+import (
+       "encoding/json"
+       "log"
+       shttp "net/http"
+
+       "jsdaj.tq/pf/internal/errors"
+)
+
+type httpError struct {
+       Status  int    `json:"status"`
+       Message string `json:"message"`
+}
+
+func HandleError(w shttp.ResponseWriter, status int, message string) {
+       response := httpError{
+               Status:  status,
+               Message: message,
+       }
+
+       body, err := json.Marshal(response)
+       if err != nil {
+               body = []byte("Something went wrong")
+       }
+
+       w.WriteHeader(status)
+       w.Write(body)
+}
+
+func HandleErrorByCode(w shttp.ResponseWriter, status int) {
+       switch status {
+       case shttp.StatusBadRequest:
+               HandleError(w, status, "Bad body")
+       default:
+               HandleError(w, shttp.StatusInternalServerError, "Something went wrong")
+       }
+}
+
+func HandleServiceError(w shttp.ResponseWriter, err error) {
+       switch err := err.(type) {
+       case errors.Error:
+               status := err.Code.MapToHTTP()
+               HandleError(w, status, err.Message)
+       default:
+               log.Printf("error: Expecting 'services.Error', received: %s\n", err)
+               HandleErrorByCode(w, shttp.StatusInternalServerError)
+       }
+}
similarity index 88%
rename from pkg/http/middlewares.go
rename to pkg/http/util/middlewares.go
index c432172fe3791ac4c4be470ba9b4f94bac53df77..1edeef3601edeb42dba7ac9d63c0444d993bf2eb 100644 (file)
@@ -1,4 +1,4 @@
-package http
+package util
 
 import (
        "log"
@@ -19,6 +19,6 @@ func middlewareJson(next shttp.Handler) shttp.Handler {
        })
 }
 
-func middlewares(next shttp.Handler) shttp.Handler {
+func Middlewares(next shttp.Handler) shttp.Handler {
        return middlewareLog(middlewareJson(next))
 }
diff --git a/pkg/http/util/parsers.go b/pkg/http/util/parsers.go
new file mode 100644 (file)
index 0000000..cee58be
--- /dev/null
@@ -0,0 +1,28 @@
+package util
+
+import (
+       "encoding/json"
+       "log"
+       "net/http"
+)
+
+func ParseRequestAndErr[T any](w http.ResponseWriter, r *http.Request, input T) error {
+       err := json.NewDecoder(r.Body).Decode(input)
+       if err != nil {
+               log.Printf("!! %s\n", err)
+               HandleErrorByCode(w, http.StatusBadRequest)
+               return err
+       }
+       return nil
+}
+
+func ParseAndWriteResponse[T any](w http.ResponseWriter, input T, status int) {
+       response, err := json.Marshal(input)
+       if err != nil {
+               HandleErrorByCode(w, http.StatusInternalServerError)
+               return
+       }
+
+       w.WriteHeader(status)
+       w.Write(response)
+}
diff --git a/pkg/services/errors.go b/pkg/services/errors.go
deleted file mode 100644 (file)
index 0f842bc..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package services
-
-import "fmt"
-
-type ErrorCode int
-
-const (
-       DefaultError   ErrorCode = iota
-       BadInputError 
-       ConflictError
-)
-
-func (c ErrorCode) MapToHTTP() int {
-       switch c {
-       case BadInputError:
-               return 400
-       case ConflictError:
-               return 409
-       default:
-               return 500
-       }
-}
-
-type Error struct {
-       Code ErrorCode
-       Message string
-}
-
-func (e Error) Error() string {
-       return fmt.Sprintf("(%d)%s", e.Code, e.Message)
-}
index 2b0faac06fc24768e56b19989a19f33799b677bd..48e08143b95dc50833e797ad3fa9d6a31cc97eba 100644 (file)
@@ -1,6 +1,7 @@
 package services
 
 import (
+       "jsdaj.tq/pf/internal/errors"
        "jsdaj.tq/pf/persistence"
        "jsdaj.tq/pf/pkg/core"
 )
@@ -10,30 +11,31 @@ type Ingredient struct {
 }
 
 func (s *Ingredient) Create(ingredient core.Ingredient) (*core.Ingredient, error) {
-       isMissingRequiredFields := ingredient.Name == "" || ingredient.Quantity == 0 
-       isBadName := len(ingredient.Name) < 3
-       isBadQuantity := ingredient.Quantity < 0
-
-       if isMissingRequiredFields {
-               return nil, Error{Code: BadInputError, Message: "fields required: name, quantity"}
-       }
-       if isBadName {
-               return nil, Error{Code: BadInputError, Message: "name should be have more than 2 chars"}
-       }
-       if isBadQuantity {
-               return nil, Error{Code: BadInputError, Message: "quantity should be positive"}
+       if err := ingredient.IsValid(); err != nil {
+               return nil, errors.MapError(err)
        }
 
        ingredient, err := s.repository.IngredientCreate(ingredient)
        if err != nil {
-               if err.Error() == "name_in_use" {
-                       return nil, Error{Code: ConflictError, Message: err.Error()}
-               }
-               return nil, err
+               return nil, errors.MapError(err)
        }
+
        return &ingredient, nil
 }
 
+func (s *Ingredient) Update(ingredient core.Ingredient) error {
+       if err := ingredient.IsValid(); err != nil {
+               return errors.MapError(err)
+       }
+
+       err := s.repository.IngredientUpdate(ingredient)
+       if err != nil {
+               return errors.MapError(err)
+       }
+
+       return nil
+}
+
 func (s *Ingredient) List() ([]core.Ingredient, error) {
        ingredients, err := s.repository.IngredientList()
        if err != nil {
@@ -47,4 +49,3 @@ func InitIngredientService(repository persistence.IngredientRepository) Ingredie
                repository,
        }
 }
-