arch-atlas

Marketplace Service

core/services/marketplace_service.dart

data

Overview

Two endpoints: paginated/filtered list and single-product fetch. Both hit /store/physical-products with `fields=*variants.calculated_price` so the UI gets per-region pricing in the same response.

User Flow

  1. getProducts(...filters) → GET /store/physical-products with the dynamic query map.
  2. Empty / null filters are omitted via the spread + if-condition pattern.
  3. getProductById(id) → GET /store/physical-products/:id; throws 'Product not found' for null data.

Cases & Edge Cases

  • Network errors are unwrapped (response.data['message']) when possible, then re-thrown as Exception for the controller to surface.
  • Each filter list field uses Dio's auto-encoding (?category_id=X&category_id=Y) — relies on Dio's default ListFormat.
  • title[$like] is escaped with a literal '$' in the query key — Medusa accepts that as the contains operator.

Code References

  • lib/src/core/services/marketplace_service.dart:9 // getProducts
  • lib/src/core/services/marketplace_service.dart:78 // getProductById

API Calls

  • GET/store/physical-productsno status

    Paginated catalog of physical products with combined server-side filter, sort and search.

    Request
    Query (all optional): limit, offset, q, category_id[], collection_id, tag_id[], type_id, order, is_giftcard, title[$like], variants[options][value], fields=*variants.calculated_price
    Response
    { products: Product[] }
    lib/src/features/shared/marketplace/views/marketplace_home_screen.dart + widgets/marketplace_product_list.dart

    auth: customer. title[$like] uses Medusa's contains operator (literal $).

  • GET/store/physical-products/:productId?fields=*variants.calculated_priceno status

    Fetch a single physical product (fallback when route extra is missing).

    Response
    { product: Product }
    lib/src/features/shared/product_details/views/product_details_screen.dart // loadProduct

    auth: customer.

Notes

Pagination is via offset+limit; no cursor / nextLink — the controller increments offset by the actual response length, not by limit, so a partial last page still terminates cleanly.