diff --git a/Makefile b/Makefile index 44ba89a..3467c8d 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,7 @@ .PHONY: test test: - go test -tags integration -count=1 ./... \ No newline at end of file + go test -count=1 -v -run ./... + +.PHONY: integration +integration: + go test -tags integration -count=1 -v -run "GetItemByLegacyID" ./... \ No newline at end of file diff --git a/browse.go b/browse.go index c54eef8..cc8a36d 100644 --- a/browse.go +++ b/browse.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "net/url" + "time" ) // BrowseService handles communication with the Browse API @@ -27,6 +28,169 @@ func OptBrowseContextualLocation(country, zip string) func(*http.Request) { } } +// LegacyItem represents the legacy representation of an eBay item. +type LegacyItem struct { + ItemID string `json:"itemId"` + SellerItemRevision string `json:"sellerItemRevision"` + Title string `json:"title"` + ShortDescription string `json:"shortDescription"` + Price struct { + Value string `json:"value"` + Currency string `json:"currency"` + } `json:"price"` + CategoryPath string `json:"categoryPath"` + Condition string `json:"condition"` + ConditionID string `json:"conditionId"` + ItemLocation struct { + City string `json:"city"` + StateOrProvince string `json:"stateOrProvince"` + PostalCode string `json:"postalCode"` + Country string `json:"country"` + } `json:"itemLocation"` + Image struct { + ImageURL string `json:"imageUrl"` + } `json:"image"` + AdditionalImages []struct { + ImageURL string `json:"imageUrl"` + } `json:"additionalImages"` + Brand string `json:"brand"` + ItemEndDate time.Time `json:"itemEndDate"` + Seller struct { + Username string `json:"username"` + FeedbackPercentage string `json:"feedbackPercentage"` + FeedbackScore int `json:"feedbackScore"` + } `json:"seller"` + Gtin string `json:"gtin"` + EstimatedAvailabilities []struct { + DeliveryOptions []string `json:"deliveryOptions"` + EstimatedAvailabilityStatus string `json:"estimatedAvailabilityStatus"` + EstimatedAvailableQuantity int `json:"estimatedAvailableQuantity"` + EstimatedSoldQuantity int `json:"estimatedSoldQuantity"` + } `json:"estimatedAvailabilities"` + ShippingOptions []struct { + ShippingServiceCode string `json:"shippingServiceCode"` + TrademarkSymbol string `json:"trademarkSymbol"` + ShippingCarrierCode string `json:"shippingCarrierCode"` + Type string `json:"type"` + ShippingCost struct { + Value string `json:"value"` + Currency string `json:"currency"` + } `json:"shippingCost"` + QuantityUsedForEstimate int `json:"quantityUsedForEstimate"` + MinEstimatedDeliveryDate time.Time `json:"minEstimatedDeliveryDate"` + MaxEstimatedDeliveryDate time.Time `json:"maxEstimatedDeliveryDate"` + ShipToLocationUsedForEstimate struct { + PostalCode string `json:"postalCode"` + Country string `json:"country"` + } `json:"shipToLocationUsedForEstimate"` + AdditionalShippingCostPerUnit struct { + Value string `json:"value"` + Currency string `json:"currency"` + } `json:"additionalShippingCostPerUnit"` + ShippingCostType string `json:"shippingCostType"` + } `json:"shippingOptions"` + ShipToLocations struct { + RegionIncluded []struct { + RegionName string `json:"regionName"` + RegionType string `json:"regionType"` + } `json:"regionIncluded"` + RegionExcluded []struct { + RegionName string `json:"regionName"` + RegionType string `json:"regionType"` + } `json:"regionExcluded"` + } `json:"shipToLocations"` + ReturnTerms struct { + ReturnsAccepted bool `json:"returnsAccepted"` + RefundMethod string `json:"refundMethod"` + ReturnMethod string `json:"returnMethod"` + ReturnShippingCostPayer string `json:"returnShippingCostPayer"` + ReturnPeriod struct { + Value int `json:"value"` + Unit string `json:"unit"` + } `json:"returnPeriod"` + RestockingFeePercentage string `json:"restockingFeePercentage"` + } `json:"returnTerms"` + Taxes []struct { + TaxJurisdiction struct { + Region struct { + RegionName string `json:"regionName"` + RegionType string `json:"regionType"` + } `json:"region"` + TaxJurisdictionID string `json:"taxJurisdictionId"` + } `json:"taxJurisdiction"` + TaxType string `json:"taxType"` + TaxPercentage string `json:"taxPercentage"` + ShippingAndHandlingTaxed bool `json:"shippingAndHandlingTaxed"` + IncludedInPrice bool `json:"includedInPrice"` + } `json:"taxes"` + LocalizedAspects []struct { + Type string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` + } `json:"localizedAspects"` + PrimaryProductReviewRating struct { + ReviewCount int `json:"reviewCount"` + AverageRating string `json:"averageRating"` + RatingHistograms []struct { + Rating string `json:"rating"` + Count int `json:"count"` + } `json:"ratingHistograms"` + } `json:"primaryProductReviewRating"` + TopRatedBuyingExperience bool `json:"topRatedBuyingExperience"` + BuyingOptions []string `json:"buyingOptions"` + ItemAffiliateWebURL string `json:"itemAffiliateWebUrl"` + ItemWebURL string `json:"itemWebUrl"` + Description string `json:"description"` + EnabledForGuestCheckout bool `json:"enabledForGuestCheckout"` + AdultOnly bool `json:"adultOnly"` + CategoryID string `json:"categoryId"` +} + +// GetItemByLegacyID retrieves an item by legacy ID. +// The itemID will be available in the "itemId" field: +// https://developer.ebay.com/api-docs/buy/static/api-browse.html#Legacy +// +// eBay API docs: https://developer.ebay.com/api-docs/buy/browse/resources/item/methods/getItemByLegacyId +func (s *BrowseService) GetItemByLegacyID(ctx context.Context, itemLegacyID string, opts ...Opt) (CompactItem, error) { + u := fmt.Sprintf("buy/browse/v1/item/get_item_by_legacy_id?legacy_item_id=%s", itemLegacyID) + req, err := s.client.NewRequest(http.MethodGet, u, opts...) + if err != nil { + return CompactItem{}, err + } + var it CompactItem + return it, s.client.Do(ctx, req, &it) +} + +// CompactItem represents the "COMPACT" version of an eBay item. +type CompactItem struct { + ItemID string `json:"itemId"` + SellerItemRevision string `json:"sellerItemRevision"` + Price struct { + Value string `json:"value"` + Currency string `json:"currency"` + } `json:"price"` + EstimatedAvailabilities []struct { + AvailabilityThresholdType string `json:"availabilityThresholdType"` + AvailabilityThreshold int `json:"availabilityThreshold"` + EstimatedAvailabilityStatus string `json:"estimatedAvailabilityStatus"` + EstimatedSoldQuantity int `json:"estimatedSoldQuantity"` + } `json:"estimatedAvailabilities"` + TopRatedBuyingExperience bool `json:"topRatedBuyingExperience"` +} + +// GetCompactItem retrieves the compact version of a specific item. +// +// eBay API docs: https://developer.ebay.com/api-docs/buy/browse/resources/item/methods/getItem +func (s *BrowseService) GetCompactItem(ctx context.Context, itemID string, opts ...Opt) (CompactItem, error) { + u := fmt.Sprintf("buy/browse/v1/item/%s?fieldgroups=COMPACT", itemID) + req, err := s.client.NewRequest(http.MethodGet, u, opts...) + if err != nil { + return CompactItem{}, err + } + var it CompactItem + return it, s.client.Do(ctx, req, &it) +} + // Item represents an eBay item. type Item struct { AdditionalImages []struct { @@ -304,11 +468,10 @@ type Item struct { } // GetItem retrieves the details of a specific item. -// Fieldgroups valid values are "PRODUCT" and "COMPACT". // // eBay API docs: https://developer.ebay.com/api-docs/buy/browse/resources/item/methods/getItem -func (s *BrowseService) GetItem(ctx context.Context, itemID string, fieldgroups string, opts ...Opt) (Item, error) { - u := fmt.Sprintf("buy/browse/v1/item/%s?fieldgroups=%s", itemID, fieldgroups) +func (s *BrowseService) GetItem(ctx context.Context, itemID string, opts ...Opt) (Item, error) { + u := fmt.Sprintf("buy/browse/v1/item/%s?fieldgroups=PRODUCT", itemID) req, err := s.client.NewRequest(http.MethodGet, u, opts...) if err != nil { return Item{}, err diff --git a/browse_test.go b/browse_test.go index 3eebd4f..a8f34f0 100644 --- a/browse_test.go +++ b/browse_test.go @@ -28,11 +28,10 @@ func TestGetItem(t *testing.T) { defer teardown() mux.HandleFunc("/buy/browse/v1/item/v1|202117468662|0", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{"itemId": "v1|202117468662|0", "title": "%s"}`, r.URL.Query().Get("fieldgroups")) + fmt.Fprintf(w, `{"itemId": "%s"}`, r.URL.Query().Get("fieldgroups")) }) - item, err := client.Buy.Browse.GetItem(context.Background(), "v1|202117468662|0", "COMPACT") + item, err := client.Buy.Browse.GetCompactItem(context.Background(), "v1|202117468662|0") assert.Nil(t, err) - assert.Equal(t, "v1|202117468662|0", item.ItemID) - assert.Equal(t, "COMPACT", item.Title) + assert.Equal(t, "COMPACT", item.ItemID) } diff --git a/test/integration/ebay_test.go b/test/integration/ebay_test.go index 1538ca6..fa96b00 100644 --- a/test/integration/ebay_test.go +++ b/test/integration/ebay_test.go @@ -44,3 +44,14 @@ func TestAuthorization(t *testing.T) { t.Log(into) } } + +// https://developer.ebay.com/my/api_test_tool?index=0&api=browse&call=item_summary_search__GET&variation=json +func TestGetItemByLegacyID(t *testing.T) { + it, err := client.Buy.Browse.GetItemByLegacyID(context.Background(), "110436963416") + if err != nil { + t.Fatal(err) + } + if testing.Verbose() { + t.Logf("%+v", it) + } +}