}
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()}
+ switch err := err.(type) {
+ case Error:
+ return err
default:
- return Error{Code: DefaultError, Message: "Something bad happened"}
+ 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"}
+ }
}
}
type Ingredient struct {
Id int `json:"id,omitempty"`
Name string `json:"name"`
- Quantity int `json:"quantity"`
+ Quantity *int `json:"quantity"`
Description string `json:"description"`
CreatedAt *time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
}
func (ingredient Ingredient) IsValid() error {
- isMissingRequiredFields := ingredient.Name == "" || ingredient.Quantity == 0
+ isMissingRequiredFields := ingredient.Name == "" || ingredient.Quantity == nil
isBadName := len(ingredient.Name) < 3
- isBadQuantity := ingredient.Quantity < 0
+ isBadQuantity := *ingredient.Quantity < 0
if isMissingRequiredFields {
return errors.Error{Code: errors.BadInputError, Message: "fields required: name, quantity"}
ingredient, err := s.ingredients.Create(input)
if err != nil {
- util.HandleServiceError(w, err)
+ util.HandleServiceError(w, r, err)
return
}
- util.ParseAndWriteResponse(w, ingredient, shttp.StatusCreated)
+ util.ParseAndWriteResponse(w, r, ingredient, shttp.StatusCreated)
}
func (s *Server) ingredientHandleUpdate(w shttp.ResponseWriter, r *shttp.Request) {
err = s.ingredients.Update(ingredient)
if err != nil {
- util.HandleServiceError(w, err)
+ util.HandleServiceError(w, r, err)
return
}
- util.ParseAndWriteResponse(w, ingredient, shttp.StatusOK)
+ util.ParseAndWriteResponse(w, r, ingredient, shttp.StatusOK)
}
func (s *Server) ingredientHandleDelete(w shttp.ResponseWriter, r *shttp.Request) {
err = s.ingredients.Delete(id)
if err != nil {
- util.HandleServiceError(w, err)
+ util.HandleServiceError(w, r, err)
return
}
- util.ParseAndWriteResponse(w, struct{}{}, shttp.StatusNoContent)
+ util.ParseAndWriteResponse(w, r, struct{}{}, shttp.StatusNoContent)
}
func (s *Server) ingredientHandleGet(w shttp.ResponseWriter, r *shttp.Request) {
in, err := s.ingredients.Get(id)
if err != nil {
- util.HandleServiceError(w, err)
+ util.HandleServiceError(w, r, err)
return
}
- util.ParseAndWriteResponse(w, in, shttp.StatusOK)
+ util.ParseAndWriteResponse(w, r, in, shttp.StatusOK)
}
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())
+ util.HandleError(w, r, shttp.StatusInternalServerError, err.Error())
return
}
- util.ParseAndWriteResponse(w, ingredients, shttp.StatusOK)
+ util.ParseAndWriteResponse(w, r, ingredients, shttp.StatusOK)
}
shttp "net/http"
"jsdaj.tq/pf/internal/errors"
+ "jsdaj.tq/pf/pkg/util"
)
type httpError struct {
Message string `json:"message"`
}
-func HandleError(w shttp.ResponseWriter, status int, message string) {
+func HandleError(w shttp.ResponseWriter, r *shttp.Request, status int, message string) {
+ requestId := r.Context().Value(RequestId).(string)
+
+ log.Printf("%s!! %s :: %d :: %s%s\n", util.Red, requestId, status, message, util.Reset)
+
response := httpError{
Status: status,
Message: message,
w.Write(body)
}
-func HandleErrorByCode(w shttp.ResponseWriter, status int) {
+func HandleErrorByCode(w shttp.ResponseWriter, r *shttp.Request, status int) {
switch status {
case shttp.StatusBadRequest:
- HandleError(w, status, "Bad body")
+ HandleError(w, r, status, "Bad body")
default:
- HandleError(w, shttp.StatusInternalServerError, "Something went wrong")
+ HandleError(w, r, shttp.StatusInternalServerError, "Something went wrong")
}
}
-func HandleServiceError(w shttp.ResponseWriter, err error) {
+func HandleServiceError(w shttp.ResponseWriter, r *shttp.Request, err error) {
switch err := err.(type) {
case errors.Error:
status := err.Code.MapToHTTP()
- HandleError(w, status, err.Message)
+ HandleError(w, r, status, err.Message)
default:
- log.Printf("error: Expecting 'services.Error', received: %s\n", err)
- HandleErrorByCode(w, shttp.StatusInternalServerError)
+ log.Printf("%s?? Expecting 'services.Error', received: %s%s\n", util.Yellow, err, util.Reset)
+ HandleErrorByCode(w, r, shttp.StatusInternalServerError)
}
}
package util
import (
+ "context"
+ "crypto/rand"
"log"
shttp "net/http"
+
+ "jsdaj.tq/pf/pkg/util"
)
+type ContextKey string
+
+const RequestId ContextKey = "requestId"
+
func middlewareLog(next shttp.Handler) shttp.Handler {
return shttp.HandlerFunc(func(w shttp.ResponseWriter, r *shttp.Request) {
- log.Printf("New request :: %s :: %s\n", r.Method, r.URL)
+ requestId := r.Context().Value(RequestId).(string)
+
+ log.Printf("%s** %s :: %s :: %s%s\n", util.White, requestId, r.Method, r.URL, util.Reset)
next.ServeHTTP(w, r)
})
}
})
}
+func middlewareId(next shttp.Handler) shttp.Handler {
+ return shttp.HandlerFunc(func(w shttp.ResponseWriter, r *shttp.Request) {
+ ctx := context.WithValue(r.Context(), RequestId, rand.Text())
+ req := r.WithContext(ctx)
+ next.ServeHTTP(w, req)
+ })
+}
+
func Middlewares(next shttp.Handler) shttp.Handler {
- return middlewareLog(middlewareJson(next))
+ return middlewareId(middlewareLog(middlewareJson(next)))
}
import (
"encoding/json"
+ serrors "errors"
"log"
"net/http"
"strconv"
- serrors "errors"
"jsdaj.tq/pf/internal/errors"
+ "jsdaj.tq/pf/pkg/util"
)
func ParseParamIdAndErr(w http.ResponseWriter, r *http.Request) (int, error) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
- HandleServiceError(w, errors.MapError(serrors.New("bad_id")))
+ HandleServiceError(w, r, errors.MapError(serrors.New("bad_id")))
return 0, err
}
return id, nil
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)
+ HandleErrorByCode(w, r, http.StatusBadRequest)
return err
}
return nil
}
-func ParseAndWriteResponse[T any](w http.ResponseWriter, input T, status int) {
+func ParseAndWriteResponse[T any](w http.ResponseWriter, r *http.Request, input T, status int) {
+ requestId := r.Context().Value(RequestId).(string)
+
response, err := json.Marshal(input)
if err != nil {
- HandleErrorByCode(w, http.StatusInternalServerError)
+ HandleErrorByCode(w, r, http.StatusInternalServerError)
return
}
w.WriteHeader(status)
w.Write(response)
+ log.Printf("%s** %s :: %d%s\n", util.Green, requestId, status, util.Reset)
}
--- /dev/null
+package util
+
+type Color string
+
+const (
+ Red Color = "\x1b[31m"
+ Yellow Color = "\x1b[33m"
+ Green Color = "\x1b[32m"
+ White Color = "\x1b[97m"
+ Reset Color = "\x1b[0m"
+)