diff --git a/internal/http-server/handlers/recipe/recipe.go b/internal/http-server/handlers/recipe/recipe.go index 2318945..e138c06 100644 --- a/internal/http-server/handlers/recipe/recipe.go +++ b/internal/http-server/handlers/recipe/recipe.go @@ -66,11 +66,9 @@ func New(log *slog.Logger, recipeProvider RecipeProvider) http.HandlerFunc { return } // render response - var resp Response = Response{ + render.JSON(w, r, Response{ Response: resp.OK(), Recipe: recipe, - } - log.Debug("response", slog.Any("resp", resp)) - render.JSON(w, r, resp) + }) } } diff --git a/internal/http-server/handlers/recipes/recipes.go b/internal/http-server/handlers/recipes/recipes.go new file mode 100644 index 0000000..5e3faa7 --- /dev/null +++ b/internal/http-server/handlers/recipes/recipes.go @@ -0,0 +1,70 @@ +package recipes + +import ( + "context" + "log/slog" + "net/http" + "recipes/internal/domain/models" + resp "recipes/internal/lib/api/response" + "recipes/internal/lib/logger/sl" + + "github.com/go-chi/chi/v5/middleware" + "github.com/go-chi/render" + "github.com/go-playground/validator/v10" +) + +type Request struct { + Page uint `json:"page" validate:"required,gt=0"` +} + +type Response struct { + resp.Response + Recipes []models.Recipe `json:"recipes"` +} + +type RecipeProvider interface { + GetRecipes(ctx context.Context, offset, limit int) ([]models.Recipe, error) +} + +const getRecipesLimit int = 16 + +func New(log *slog.Logger, recipeProvider RecipeProvider) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + const op = "http-server.handlers.recipes.New" + + log = log.With( + slog.String("op", op), + slog.String("request_id", middleware.GetReqID(r.Context())), + ) + + var req Request + // decode request + err := render.DecodeJSON(r.Body, &req) + if err != nil { + log.Error("failed to decode request body", sl.Err(err)) + render.JSON(w, r, resp.Error("failed to decode request")) + return + } + log.Debug("request body decoded", slog.Any("request", req)) + // validate request + if err := validator.New().Struct(req); err != nil { + validateErr := err.(validator.ValidationErrors) + + log.Error("invalid request", sl.Err(err)) + render.JSON(w, r, resp.ValidationError(validateErr)) + return + } + // get from storage + recipes, err := recipeProvider.GetRecipes(r.Context(), getRecipesLimit*(int(req.Page)-1), getRecipesLimit) + if err != nil { + log.Error("failed to get recipes from storage", sl.Err(err)) + render.JSON(w, r, resp.Error("failed to get recipes")) + return + } + // return + render.JSON(w, r, Response{ + Response: resp.OK(), + Recipes: recipes, + }) + } +}