- 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.