Org Web Adapter

hungryroot/api/filter-pairings-v1-v2-parity.org

ID
da036753-b797-4b5f-80c3-f5428a3340cd

GET /api/filter_pairings/ — V1 vs V2 Parity Investigation

Source

- Confluence: hungryroot.atlassian.net/wiki/spaces/BA/pages/889749506 (v1 → v2 API migration guide)

- Doc status: =Not Ready for migration=

- Tracking: [[https://hungryroot.atlassian.net/browse/BE-5965][BE-5965]], [[https://hungryroot.atlassian.net/browse/BE-6141][BE-6141]]

Endpoints

- V1: =GET /api/filter_pairings/=

- V2 list: =GET /api/v2/pairings/=

- V2 swaps: =GET /api/v2/customers/{customer_id}/pairings/{id}/swaps/=

Code refs

V1

- View: =app/views/api.py:658= (=filter_pairings=)

- Service: =app/services/api/pairing.py:221= (=filter_pairings=)

- Response builder: =app/services/api/pairing.py:54-170= (=get_pairing=)

V2

- List viewset: =app/rest/pairing.py:588= (=PairingList=)

- List serializer: =app/rest/pairing.py:173-205= (=PairingListSerializer=)

- Swaps viewset: =app/rest/pairing_swaps.py:147= (=PairingSwaps=)

- Swaps serializer: =app/rest/pairing_swaps.py:84-113= (=SwappablePairingDetailSerializer=)

Query param parity

| Param | V1 | V2 | Notes |

|--------------------------+----+-----+------------------------------------------|

| is_popular | ✓ | ✓ | V1 maps to TOP_RATED tag |

| is_seasonal | ✓ | ✓ | V1 maps to PROMOTIONAL_TAG |

| is_recent | ✓ | ✓ | requires customer_id |

| is_new | ✓ | ✓ | V1 maps to NEW_RECIPE tag |

| is_marketing/marketing_tags | ✓ | ✓ | OR semantics |

| dish_type(s) | ✓ | ✓ | V2: =dish_types=X,Y= |

| max_cooking_time | ✓ | ✓ | |

| dietary filters | ✓ | ✓ | V2 via DietaryFiltersMixin |

| search_query | ✓ | ✗ | SearchFilter not wired in PairingFilter |

| order_id | ✓ | ✗ | drives inventory + dietary_restricted |

| swap_ingredients_recipe | ✓ | ~ | V2 split to path-param swaps endpoint |

| max_calories | ✓ | ✗ | V2 only has has_max_calories tag filter |

| serving_size | ✓ | ✗ | |

Response field deltas

V1 base fields

=id, name, is_active, is_featured, average_rating, recipe_score, featured_img,

featured_quote, sort_order, points, short_instruction_html, cooking_time,

calories, servings, num_ratings, dish_type, slug, spicy_level, badges,

is_ratable, tags, ingredients=

V1 conditional (=includes== param)

- =details= → nutrition_html

- =ingredients_dict=

- =rating= → liked, rating, date_rated

- =favorite= → is_favorited

- =total_count= → in response root

- =ingredient_discount= → discount fields on ingredients

V2 list fields

=average_rating, cooking_time, id, is_featured, featured_img_url,

featured_quote, name, num_ratings, nutrition_info, points, recipe_score,

servings, short_instruction_html, slug, liked, sort_order, spicy_level,

tags, ingredients, feedback_modal_eligible, nutrition=

Missing in V2

- =is_active= (only active pairings returned)

- =featured_img= (renamed to =featured_img_url=)

- =is_ratable=

- =remaining_inventory= (V1 has when order provided)

- =dietary_restricted= (V1 has when order provided)

Added in V2

- =nutrition= object (always; V1 only via =includes=details=)

- =feedback_modal_eligible=

- Persistent =liked= overlay (V1 only with =includes=rating= + customer ctx)

- Paginated DRF envelope

Use-case verdict

Carousels (is_popular, is_seasonal, is_recent, is_marketing, is_new)

✓ Parity. V2 supports all four documented carousel params. Doc notes these may

go away post exp-188 anyway.

Swap ingredients

~ Partial. V1: =?order_id=X&swap_ingredients_recipe=Y= returns

={pairings, swappable_pairings}=. V2: dedicated

=/customers/{id}/pairings/{id}/swaps/= returns ={swappable_pairings}= with

identical inner structure. Migrate-able but client must restructure (query →

path params, separate call from pairings list).

Search (=search_query=)

✗ NOT migrate-able. V2 list endpoint has no full-text search; shop pages hit

Algolia direct. Doc says BE-6141 follow-up pending answer on why logged-out

shop pages don't mirror logged-in experience.

Bottom line

Carousels migrate-able. Swap-ingredients migrate-able with client refactor.

Search blocks full migration — same blocker as =filter_products=. Doc status

=Not Ready for migration= is accurate.