cooked: decode recipe lists as arrays

Amolith created

Change summary

internal/cooked/client.go                        | 12 ++++--------
internal/cooked/client_recipe_validation_test.go | 10 +++++-----
internal/cooked/client_test.go                   | 14 ++++++--------
3 files changed, 15 insertions(+), 21 deletions(-)

Detailed changes

internal/cooked/client.go 🔗

@@ -356,18 +356,18 @@ func (c *Client) DeleteRecipe(ctx context.Context, recipeID string) error {
 }
 
 func (c *Client) getRecipes(ctx context.Context, path string) ([]RecipeCard, error) {
-	var response recipeListResponse
+	var recipes []RecipeCard
 	decodeRecipes := func(decoder *json.Decoder) error {
-		return decoder.Decode(&response)
+		return decoder.Decode(&recipes)
 	}
 	if err := c.doAuthenticated(ctx, http.MethodGet, path, nil, decodeRecipes); err != nil {
 		return nil, err
 	}
-	if err := validateRecipeCards(response.Recipes); err != nil {
+	if err := validateRecipeCards(recipes); err != nil {
 		return nil, err
 	}
 
-	return response.Recipes, nil
+	return recipes, nil
 }
 
 func validateRecipeCards(recipes []RecipeCard) error {
@@ -540,10 +540,6 @@ type updateShoppingListProductGroupRequest struct {
 	Selected bool   `json:"selected"`
 }
 
-type recipeListResponse struct {
-	Recipes []RecipeCard `json:"recipes"`
-}
-
 type previewRecipeTextRequest struct {
 	RecipeName string `json:"recipe-name"`
 	RecipeText string `json:"recipe-text"`

internal/cooked/client_recipe_validation_test.go 🔗

@@ -14,7 +14,7 @@ func TestListRecipesACIDAPIClientResponses1AcceptsEmptyRecipesList(t *testing.T)
 	client, closeServer := newTestClient(t, rawRecipeListTestHandler(
 		t,
 		"/api/user/returned-user/recipes",
-		"{\"recipes\":[]}",
+		`[]`,
 	))
 	defer closeServer()
 
@@ -27,11 +27,11 @@ func TestListRecipesACIDAPIClientResponses1AcceptsEmptyRecipesList(t *testing.T)
 	}
 }
 
-func TestListRecipesACIDAPIClientResponses1RejectsMissingRecipesField(t *testing.T) {
+func TestListRecipesACIDAPIClientResponses1RejectsNullRecipesList(t *testing.T) {
 	client, closeServer := newTestClient(t, rawRecipeListTestHandler(
 		t,
 		"/api/user/returned-user/recipes",
-		`{}`,
+		`null`,
 	))
 	defer closeServer()
 
@@ -46,8 +46,8 @@ func TestSearchRecipesACIDAPIClientResponses1RejectsRecipeCardsWithoutIDOrTitle(
 		name string
 		body string
 	}{
-		{name: "missing id", body: "{\"recipes\":[{\"title\":\"Pasta\"}]}"},
-		{name: "blank title", body: "{\"recipes\":[{\"id\":\"recipe-1\",\"title\":\"   \"}]}"},
+		{name: "missing id", body: `[{"title":"Pasta"}]`},
+		{name: "blank title", body: `[{"id":"recipe-1","title":"   "}]`},
 	}
 
 	for _, tt := range tests {

internal/cooked/client_test.go 🔗

@@ -895,13 +895,11 @@ func writeShoppingListResponse(t *testing.T, w http.ResponseWriter) {
 func writeRecipeListResponse(t *testing.T, w http.ResponseWriter) {
 	t.Helper()
 
-	writeJSON(t, w, recipeListResponse{
-		Recipes: []RecipeCard{{
-			ID:           "recipe-1",
-			Title:        "Pasta",
-			ThumbnailURL: "https://example.invalid/thumb.jpg",
-		}},
-	})
+	writeJSON(t, w, []RecipeCard{{
+		ID:           "recipe-1",
+		Title:        "Pasta",
+		ThumbnailURL: "https://example.invalid/thumb.jpg",
+	}})
 }
 
 func writeRecipeMetadataResponse(t *testing.T, w http.ResponseWriter) {
@@ -919,7 +917,7 @@ func writeRecipeMetadataResponse(t *testing.T, w http.ResponseWriter) {
 }
 
 func writeJSON[
-	T loginResponse | shoppingListResponse | recipeListResponse | RecipeContent | RecipeTextPreview |
+	T loginResponse | shoppingListResponse | []RecipeCard | RecipeContent | RecipeTextPreview |
 		saveRecipeResponse | importRecipeURLResponse,
 ](
 	t *testing.T,