Class: Retailer::CostcoApi

Inherits:
Object
  • Object
show all
Defined in:
app/services/retailer/costco_api.rb

Overview

Client for Costco.ca's product price and inventory APIs.

Costco groups every variant of a product under one parent URL with no
per-variant page, so scraping the rendered page only ever yields the
page-default variant. These JSON APIs are keyed by the Costco item
number (our third_party_part_number) and return accurate per-variant
data without rendering:

  • Price: display-price-lite on the gdx-api.costco.com gateway —
    needs the Client-Identifier header credential.
  • Stock: AjaxSCInventoryUpdate on www.costco.ca — needs the
    clientId query parameter.

Credentials are discovered and cached by CostcoCredentials;
an auth rejection triggers one credential refresh and retry.

Examples:

result = Retailer::CostcoApi.new.probe('1128877')
result.price       # => 299.99
result.available   # => true

Defined Under Namespace

Classes: Result

Constant Summary collapse

INVENTORY_URL =

Inventory endpoint (stable WCS path on the main domain).

'https://www.costco.ca/AjaxSCInventoryUpdate'
USER_AGENT =

Costco's gateway rejects non-browser user agents; mirror a real one.

'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ' \
'(KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36'
LOCALE =
'en-ca'
TIMEOUT =

seconds

20

Instance Method Summary collapse

Instance Method Details

#probe(item_number) ⇒ Result

Look up price and availability for one Costco item number.

Parameters:

  • item_number (String)

    the Costco item number (retailer SKU)

Returns:



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'app/services/retailer/costco_api.rb', line 62

def probe(item_number)
  price_data = fetch_price_with_retry(item_number)
  return Result.new(success: false, error: price_data[:error]) unless price_data[:ok]

  Result.new(
    success: true,
    price: price_data[:price],
    currency: price_data[:currency],
    regular_price: price_data[:regular_price],
    available: fetch_inventory(item_number)
  )
rescue StandardError => e
  Rails.logger.error "[CostcoApi] #{e.class}: #{e.message}"
  Result.new(success: false, error: "#{e.class}: #{e.message}")
end