mirror of
https://github.com/cubixle/ebay.git
synced 2026-04-24 19:54:47 +01:00
Add tests and continue integration test
This commit is contained in:
2
Makefile
2
Makefile
@@ -4,4 +4,4 @@ test:
|
|||||||
|
|
||||||
.PHONY: integration
|
.PHONY: integration
|
||||||
integration:
|
integration:
|
||||||
go test -tags integration -count=1 -v -run "GetItemByLegacyID" ./...
|
go test -count=1 -v -run "Auction" ./test/integration -integration=true
|
||||||
392
browse.go
392
browse.go
@@ -13,12 +13,19 @@ import (
|
|||||||
// eBay API docs: https://developer.ebay.com/api-docs/buy/browse/overview.html
|
// eBay API docs: https://developer.ebay.com/api-docs/buy/browse/overview.html
|
||||||
type BrowseService service
|
type BrowseService service
|
||||||
|
|
||||||
|
// Valid values of the "buyingOptions" array for items.
|
||||||
|
const (
|
||||||
|
BrowseBuyingOptionAuction = "AUCTION"
|
||||||
|
BrowseBuyingOptionFixedPrice = "FIXED_PRICE"
|
||||||
|
)
|
||||||
|
|
||||||
// OptBrowseContextualLocation adds the header containing contextualLocation.
|
// OptBrowseContextualLocation adds the header containing contextualLocation.
|
||||||
// It is strongly recommended that you use it when submitting Browse API methods.
|
// It is strongly recommended that you use it when submitting Browse API methods.
|
||||||
//
|
//
|
||||||
// eBay API docs: https://developer.ebay.com/api-docs/buy/static/api-browse.html#Headers
|
// eBay API docs: https://developer.ebay.com/api-docs/buy/static/api-browse.html#Headers
|
||||||
func OptBrowseContextualLocation(country, zip string) func(*http.Request) {
|
func OptBrowseContextualLocation(country, zip string) func(*http.Request) {
|
||||||
return func(req *http.Request) {
|
return func(req *http.Request) {
|
||||||
|
const headerEndUserCtx = "X-EBAY-C-ENDUSERCTX"
|
||||||
v := req.Header.Get(headerEndUserCtx)
|
v := req.Header.Get(headerEndUserCtx)
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
v += ","
|
v += ","
|
||||||
@@ -193,278 +200,167 @@ func (s *BrowseService) GetCompactItem(ctx context.Context, itemID string, opts
|
|||||||
|
|
||||||
// Item represents an eBay item.
|
// Item represents an eBay item.
|
||||||
type Item struct {
|
type Item struct {
|
||||||
AdditionalImages []struct {
|
ItemID string `json:"itemId"`
|
||||||
Height string `json:"height"`
|
SellerItemRevision string `json:"sellerItemRevision"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Subtitle string `json:"subtitle"`
|
||||||
|
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"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
} `json:"itemLocation"`
|
||||||
|
Image struct {
|
||||||
|
ImageURL string `json:"imageUrl"`
|
||||||
|
} `json:"image"`
|
||||||
|
AdditionalImages []struct {
|
||||||
ImageURL string `json:"imageUrl"`
|
ImageURL string `json:"imageUrl"`
|
||||||
Width string `json:"width"`
|
|
||||||
} `json:"additionalImages"`
|
} `json:"additionalImages"`
|
||||||
AdultOnly string `json:"adultOnly"`
|
MarketingPrice struct {
|
||||||
AgeGroup string `json:"ageGroup"`
|
OriginalPrice struct {
|
||||||
BidCount string `json:"bidCount"`
|
Value string `json:"value"`
|
||||||
Brand string `json:"brand"`
|
Currency string `json:"currency"`
|
||||||
BuyingOptions []string `json:"buyingOptions"`
|
} `json:"originalPrice"`
|
||||||
CategoryID string `json:"categoryId"`
|
DiscountPercentage string `json:"discountPercentage"`
|
||||||
CategoryPath string `json:"categoryPath"`
|
DiscountAmount struct {
|
||||||
Color string `json:"color"`
|
Value string `json:"value"`
|
||||||
Condition string `json:"condition"`
|
Currency string `json:"currency"`
|
||||||
ConditionID string `json:"conditionId"`
|
} `json:"discountAmount"`
|
||||||
CurrentBidPrice struct {
|
} `json:"marketingPrice"`
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
Color string `json:"color"`
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
Brand string `json:"brand"`
|
||||||
Currency string `json:"currency"`
|
Seller struct {
|
||||||
Value string `json:"value"`
|
Username string `json:"username"`
|
||||||
} `json:"currentBidPrice"`
|
FeedbackPercentage string `json:"feedbackPercentage"`
|
||||||
Description string `json:"description"`
|
FeedbackScore int `json:"feedbackScore"`
|
||||||
EnabledForGuestCheckout string `json:"enabledForGuestCheckout"`
|
} `json:"seller"`
|
||||||
EnergyEfficiencyClass string `json:"energyEfficiencyClass"`
|
Gtin string `json:"gtin"`
|
||||||
|
Mpn string `json:"mpn"`
|
||||||
Epid string `json:"epid"`
|
Epid string `json:"epid"`
|
||||||
EstimatedAvailabilities []struct {
|
EstimatedAvailabilities []struct {
|
||||||
AvailabilityThreshold string `json:"availabilityThreshold"`
|
|
||||||
AvailabilityThresholdType string `json:"availabilityThresholdType"`
|
|
||||||
DeliveryOptions []string `json:"deliveryOptions"`
|
DeliveryOptions []string `json:"deliveryOptions"`
|
||||||
|
AvailabilityThresholdType string `json:"availabilityThresholdType"`
|
||||||
|
AvailabilityThreshold int `json:"availabilityThreshold"`
|
||||||
EstimatedAvailabilityStatus string `json:"estimatedAvailabilityStatus"`
|
EstimatedAvailabilityStatus string `json:"estimatedAvailabilityStatus"`
|
||||||
EstimatedAvailableQuantity string `json:"estimatedAvailableQuantity"`
|
EstimatedSoldQuantity int `json:"estimatedSoldQuantity"`
|
||||||
EstimatedSoldQuantity string `json:"estimatedSoldQuantity"`
|
|
||||||
} `json:"estimatedAvailabilities"`
|
} `json:"estimatedAvailabilities"`
|
||||||
Gender string `json:"gender"`
|
ShippingOptions []struct {
|
||||||
Gtin string `json:"gtin"`
|
ShippingServiceCode string `json:"shippingServiceCode"`
|
||||||
Image struct {
|
Type string `json:"type"`
|
||||||
Height string `json:"height"`
|
ShippingCost struct {
|
||||||
ImageURL string `json:"imageUrl"`
|
Value string `json:"value"`
|
||||||
Width string `json:"width"`
|
Currency string `json:"currency"`
|
||||||
} `json:"image"`
|
|
||||||
InferredEpid string `json:"inferredEpid"`
|
|
||||||
ItemAffiliateWebURL string `json:"itemAffiliateWebUrl"`
|
|
||||||
ItemEndDate string `json:"itemEndDate"`
|
|
||||||
ItemID string `json:"itemId"`
|
|
||||||
ItemLocation struct {
|
|
||||||
AddressLine1 string `json:"addressLine1"`
|
|
||||||
AddressLine2 string `json:"addressLine2"`
|
|
||||||
City string `json:"city"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
County string `json:"county"`
|
|
||||||
PostalCode string `json:"postalCode"`
|
|
||||||
StateOrProvince string `json:"stateOrProvince"`
|
|
||||||
} `json:"itemLocation"`
|
|
||||||
ItemWebURL string `json:"itemWebUrl"`
|
|
||||||
LocalizedAspects []struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"localizedAspects"`
|
|
||||||
MarketingPrice struct {
|
|
||||||
DiscountAmount struct {
|
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"discountAmount"`
|
|
||||||
DiscountPercentage string `json:"discountPercentage"`
|
|
||||||
OriginalPrice struct {
|
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"originalPrice"`
|
|
||||||
} `json:"marketingPrice"`
|
|
||||||
Material string `json:"material"`
|
|
||||||
MinimumPriceToBid struct {
|
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"minimumPriceToBid"`
|
|
||||||
Mpn string `json:"mpn"`
|
|
||||||
Pattern string `json:"pattern"`
|
|
||||||
Price struct {
|
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"price"`
|
|
||||||
PriceDisplayCondition string `json:"priceDisplayCondition"`
|
|
||||||
PrimaryItemGroup struct {
|
|
||||||
ItemGroupAdditionalImages []struct {
|
|
||||||
Height string `json:"height"`
|
|
||||||
ImageURL string `json:"imageUrl"`
|
|
||||||
Width string `json:"width"`
|
|
||||||
} `json:"itemGroupAdditionalImages"`
|
|
||||||
ItemGroupHref string `json:"itemGroupHref"`
|
|
||||||
ItemGroupID string `json:"itemGroupId"`
|
|
||||||
ItemGroupImage struct {
|
|
||||||
Height string `json:"height"`
|
|
||||||
ImageURL string `json:"imageUrl"`
|
|
||||||
Width string `json:"width"`
|
|
||||||
} `json:"itemGroupImage"`
|
|
||||||
ItemGroupTitle string `json:"itemGroupTitle"`
|
|
||||||
ItemGroupType string `json:"itemGroupType"`
|
|
||||||
} `json:"primaryItemGroup"`
|
|
||||||
PrimaryProductReviewRating struct {
|
|
||||||
AverageRating string `json:"averageRating"`
|
|
||||||
RatingHistograms []struct {
|
|
||||||
Count string `json:"count"`
|
|
||||||
Rating string `json:"rating"`
|
|
||||||
} `json:"ratingHistograms"`
|
|
||||||
ReviewCount string `json:"reviewCount"`
|
|
||||||
} `json:"primaryProductReviewRating"`
|
|
||||||
Product struct {
|
|
||||||
AdditionalImages []struct {
|
|
||||||
Height string `json:"height"`
|
|
||||||
ImageURL string `json:"imageUrl"`
|
|
||||||
Width string `json:"width"`
|
|
||||||
} `json:"additionalImages"`
|
|
||||||
AdditionalProductIdentities []struct {
|
|
||||||
ProductIdentity []struct {
|
|
||||||
IdentifierType string `json:"identifierType"`
|
|
||||||
IdentifierValue string `json:"identifierValue"`
|
|
||||||
} `json:"productIdentity"`
|
|
||||||
} `json:"additionalProductIdentities"`
|
|
||||||
AspectGroups []struct {
|
|
||||||
Aspects []struct {
|
|
||||||
LocalizedName string `json:"localizedName"`
|
|
||||||
LocalizedValues []string `json:"localizedValues"`
|
|
||||||
} `json:"aspects"`
|
|
||||||
LocalizedGroupName string `json:"localizedGroupName"`
|
|
||||||
} `json:"aspectGroups"`
|
|
||||||
Brand string `json:"brand"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Gtins []string `json:"gtins"`
|
|
||||||
Image struct {
|
|
||||||
Height string `json:"height"`
|
|
||||||
ImageURL string `json:"imageUrl"`
|
|
||||||
Width string `json:"width"`
|
|
||||||
} `json:"image"`
|
|
||||||
Mpns []string `json:"mpns"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
} `json:"product"`
|
|
||||||
ProductFicheWebURL string `json:"productFicheWebUrl"`
|
|
||||||
QuantityLimitPerBuyer string `json:"quantityLimitPerBuyer"`
|
|
||||||
ReservePriceMet string `json:"reservePriceMet"`
|
|
||||||
ReturnTerms struct {
|
|
||||||
ExtendedHolidayReturnsOffered string `json:"extendedHolidayReturnsOffered"`
|
|
||||||
RefundMethod string `json:"refundMethod"`
|
|
||||||
RestockingFeePercentage string `json:"restockingFeePercentage"`
|
|
||||||
ReturnInstructions string `json:"returnInstructions"`
|
|
||||||
ReturnMethod string `json:"returnMethod"`
|
|
||||||
ReturnPeriod struct {
|
|
||||||
Unit string `json:"unit"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"returnPeriod"`
|
|
||||||
ReturnsAccepted string `json:"returnsAccepted"`
|
|
||||||
ReturnShippingCostPayer string `json:"returnShippingCostPayer"`
|
|
||||||
} `json:"returnTerms"`
|
|
||||||
Seller struct {
|
|
||||||
FeedbackPercentage string `json:"feedbackPercentage"`
|
|
||||||
FeedbackScore string `json:"feedbackScore"`
|
|
||||||
SellerAccountType string `json:"sellerAccountType"`
|
|
||||||
SellerLegalInfo struct {
|
|
||||||
Email string `json:"email"`
|
|
||||||
Fax string `json:"fax"`
|
|
||||||
Imprint string `json:"imprint"`
|
|
||||||
LegalContactFirstName string `json:"legalContactFirstName"`
|
|
||||||
LegalContactLastName string `json:"legalContactLastName"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Phone string `json:"phone"`
|
|
||||||
RegistrationNumber string `json:"registrationNumber"`
|
|
||||||
SellerProvidedLegalAddress struct {
|
|
||||||
AddressLine1 string `json:"addressLine1"`
|
|
||||||
AddressLine2 string `json:"addressLine2"`
|
|
||||||
City string `json:"city"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
CountryName string `json:"countryName"`
|
|
||||||
County string `json:"county"`
|
|
||||||
PostalCode string `json:"postalCode"`
|
|
||||||
StateOrProvince string `json:"stateOrProvince"`
|
|
||||||
} `json:"sellerProvidedLegalAddress"`
|
|
||||||
TermsOfService string `json:"termsOfService"`
|
|
||||||
VatDetails []struct {
|
|
||||||
IssuingCountry string `json:"issuingCountry"`
|
|
||||||
VatID string `json:"vatId"`
|
|
||||||
} `json:"vatDetails"`
|
|
||||||
} `json:"sellerLegalInfo"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
} `json:"seller"`
|
|
||||||
SellerItemRevision string `json:"sellerItemRevision"`
|
|
||||||
ShippingOptions []struct {
|
|
||||||
AdditionalShippingCostPerUnit struct {
|
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"additionalShippingCostPerUnit"`
|
|
||||||
CutOffDateUsedForEstimate string `json:"cutOffDateUsedForEstimate"`
|
|
||||||
MaxEstimatedDeliveryDate string `json:"maxEstimatedDeliveryDate"`
|
|
||||||
MinEstimatedDeliveryDate string `json:"minEstimatedDeliveryDate"`
|
|
||||||
QuantityUsedForEstimate string `json:"quantityUsedForEstimate"`
|
|
||||||
ShippingCarrierCode string `json:"shippingCarrierCode"`
|
|
||||||
ShippingCost struct {
|
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
} `json:"shippingCost"`
|
} `json:"shippingCost"`
|
||||||
ShippingCostType string `json:"shippingCostType"`
|
QuantityUsedForEstimate int `json:"quantityUsedForEstimate"`
|
||||||
ShippingServiceCode string `json:"shippingServiceCode"`
|
MinEstimatedDeliveryDate time.Time `json:"minEstimatedDeliveryDate"`
|
||||||
|
MaxEstimatedDeliveryDate time.Time `json:"maxEstimatedDeliveryDate"`
|
||||||
ShipToLocationUsedForEstimate struct {
|
ShipToLocationUsedForEstimate struct {
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
PostalCode string `json:"postalCode"`
|
|
||||||
} `json:"shipToLocationUsedForEstimate"`
|
} `json:"shipToLocationUsedForEstimate"`
|
||||||
TrademarkSymbol string `json:"trademarkSymbol"`
|
AdditionalShippingCostPerUnit struct {
|
||||||
Type string `json:"type"`
|
Value string `json:"value"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
} `json:"additionalShippingCostPerUnit"`
|
||||||
|
ShippingCostType string `json:"shippingCostType"`
|
||||||
} `json:"shippingOptions"`
|
} `json:"shippingOptions"`
|
||||||
ShipToLocations struct {
|
ShipToLocations struct {
|
||||||
RegionExcluded []struct {
|
|
||||||
RegionName string `json:"regionName"`
|
|
||||||
RegionType string `json:"regionType"`
|
|
||||||
} `json:"regionExcluded"`
|
|
||||||
RegionIncluded []struct {
|
RegionIncluded []struct {
|
||||||
RegionName string `json:"regionName"`
|
RegionName string `json:"regionName"`
|
||||||
RegionType string `json:"regionType"`
|
RegionType string `json:"regionType"`
|
||||||
} `json:"regionIncluded"`
|
} `json:"regionIncluded"`
|
||||||
|
RegionExcluded []struct {
|
||||||
|
RegionName string `json:"regionName"`
|
||||||
|
RegionType string `json:"regionType"`
|
||||||
|
} `json:"regionExcluded"`
|
||||||
} `json:"shipToLocations"`
|
} `json:"shipToLocations"`
|
||||||
ShortDescription string `json:"shortDescription"`
|
ReturnTerms struct {
|
||||||
Size string `json:"size"`
|
ReturnsAccepted bool `json:"returnsAccepted"`
|
||||||
SizeSystem string `json:"sizeSystem"`
|
RefundMethod string `json:"refundMethod"`
|
||||||
SizeType string `json:"sizeType"`
|
ReturnMethod string `json:"returnMethod"`
|
||||||
Subtitle string `json:"subtitle"`
|
ReturnShippingCostPayer string `json:"returnShippingCostPayer"`
|
||||||
Taxes []struct {
|
ReturnPeriod struct {
|
||||||
EbayCollectAndRemitTax string `json:"ebayCollectAndRemitTax"`
|
Value int `json:"value"`
|
||||||
IncludedInPrice string `json:"includedInPrice"`
|
Unit string `json:"unit"`
|
||||||
ShippingAndHandlingTaxed string `json:"shippingAndHandlingTaxed"`
|
} `json:"returnPeriod"`
|
||||||
TaxJurisdiction struct {
|
ReturnInstructions string `json:"returnInstructions"`
|
||||||
|
RestockingFeePercentage string `json:"restockingFeePercentage"`
|
||||||
|
} `json:"returnTerms"`
|
||||||
|
Taxes []struct {
|
||||||
|
TaxJurisdiction struct {
|
||||||
Region struct {
|
Region struct {
|
||||||
RegionName string `json:"regionName"`
|
RegionName string `json:"regionName"`
|
||||||
RegionType string `json:"regionType"`
|
RegionType string `json:"regionType"`
|
||||||
} `json:"region"`
|
} `json:"region"`
|
||||||
TaxJurisdictionID string `json:"taxJurisdictionId"`
|
TaxJurisdictionID string `json:"taxJurisdictionId"`
|
||||||
} `json:"taxJurisdiction"`
|
} `json:"taxJurisdiction"`
|
||||||
TaxPercentage string `json:"taxPercentage"`
|
TaxType string `json:"taxType"`
|
||||||
TaxType string `json:"taxType"`
|
TaxPercentage string `json:"taxPercentage"`
|
||||||
|
ShippingAndHandlingTaxed bool `json:"shippingAndHandlingTaxed"`
|
||||||
|
IncludedInPrice bool `json:"includedInPrice"`
|
||||||
} `json:"taxes"`
|
} `json:"taxes"`
|
||||||
Title string `json:"title"`
|
LocalizedAspects []struct {
|
||||||
TopRatedBuyingExperience string `json:"topRatedBuyingExperience"`
|
Type string `json:"type"`
|
||||||
UniqueBidderCount string `json:"uniqueBidderCount"`
|
Name string `json:"name"`
|
||||||
UnitPrice struct {
|
Value string `json:"value"`
|
||||||
ConvertedFromCurrency string `json:"convertedFromCurrency"`
|
} `json:"localizedAspects"`
|
||||||
ConvertedFromValue string `json:"convertedFromValue"`
|
QuantityLimitPerBuyer int `json:"quantityLimitPerBuyer"`
|
||||||
Currency string `json:"currency"`
|
PrimaryProductReviewRating struct {
|
||||||
Value string `json:"value"`
|
ReviewCount int `json:"reviewCount"`
|
||||||
} `json:"unitPrice"`
|
AverageRating string `json:"averageRating"`
|
||||||
UnitPricingMeasure string `json:"unitPricingMeasure"`
|
RatingHistograms []struct {
|
||||||
Warnings []struct {
|
Rating string `json:"rating"`
|
||||||
Category string `json:"category"`
|
Count int `json:"count"`
|
||||||
Domain string `json:"domain"`
|
} `json:"ratingHistograms"`
|
||||||
ErrorID string `json:"errorId"`
|
} `json:"primaryProductReviewRating"`
|
||||||
InputRefIds []string `json:"inputRefIds"`
|
TopRatedBuyingExperience bool `json:"topRatedBuyingExperience"`
|
||||||
LongMessage string `json:"longMessage"`
|
BuyingOptions []string `json:"buyingOptions"`
|
||||||
Message string `json:"message"`
|
ItemAffiliateWebURL string `json:"itemAffiliateWebUrl"`
|
||||||
OutputRefIds []string `json:"outputRefIds"`
|
ItemWebURL string `json:"itemWebUrl"`
|
||||||
Parameters []struct {
|
Description string `json:"description"`
|
||||||
Name string `json:"name"`
|
Product struct {
|
||||||
Value string `json:"value"`
|
AspectGroups []struct {
|
||||||
} `json:"parameters"`
|
LocalizedGroupName string `json:"localizedGroupName"`
|
||||||
Subdomain string `json:"subdomain"`
|
Aspects []struct {
|
||||||
} `json:"warnings"`
|
LocalizedName string `json:"localizedName"`
|
||||||
|
LocalizedValues []string `json:"localizedValues"`
|
||||||
|
} `json:"aspects"`
|
||||||
|
} `json:"aspectGroups"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Image struct {
|
||||||
|
ImageURL string `json:"imageUrl"`
|
||||||
|
} `json:"image"`
|
||||||
|
Gtins []string `json:"gtins"`
|
||||||
|
Brand string `json:"brand"`
|
||||||
|
Mpns []string `json:"mpns"`
|
||||||
|
AdditionalProductIdentities []struct {
|
||||||
|
ProductIdentity []struct {
|
||||||
|
IdentifierType string `json:"identifierType"`
|
||||||
|
IdentifierValue string `json:"identifierValue"`
|
||||||
|
} `json:"productIdentity"`
|
||||||
|
} `json:"additionalProductIdentities"`
|
||||||
|
} `json:"product"`
|
||||||
|
EnabledForGuestCheckout bool `json:"enabledForGuestCheckout"`
|
||||||
|
AdultOnly bool `json:"adultOnly"`
|
||||||
|
CategoryID string `json:"categoryId"`
|
||||||
|
|
||||||
|
// Fields not present in the json sample provided by eBay:
|
||||||
|
ItemEndDate time.Time `json:"itemEndDate"`
|
||||||
|
MinimumPriceToBid struct {
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
} `json:"minimumPriceToBid"`
|
||||||
|
CurrentBidPrice struct {
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
} `json:"currentBidPrice"`
|
||||||
|
UniqueBidderCount int `json:"uniqueBidderCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetItem retrieves the details of a specific item.
|
// GetItem retrieves the details of a specific item.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOptBrowseContextualLocationn(t *testing.T) {
|
func TestOptBrowseContextualLocation(t *testing.T) {
|
||||||
r, _ := http.NewRequest("", "", nil)
|
r, _ := http.NewRequest("", "", nil)
|
||||||
ebay.OptBrowseContextualLocation("US", "19406")(r)
|
ebay.OptBrowseContextualLocation("US", "19406")(r)
|
||||||
assert.Equal(t, "contextualLocation=country%3DUS%2Czip%3D19406", r.Header.Get("X-EBAY-C-ENDUSERCTX"))
|
assert.Equal(t, "contextualLocation=country%3DUS%2Czip%3D19406", r.Header.Get("X-EBAY-C-ENDUSERCTX"))
|
||||||
@@ -23,7 +23,20 @@ func TestOptBrowseContextualLocationExistingHeader(t *testing.T) {
|
|||||||
assert.Equal(t, "affiliateCampaignId=1,contextualLocation=country%3DUS%2Czip%3D19406", r.Header.Get("X-EBAY-C-ENDUSERCTX"))
|
assert.Equal(t, "affiliateCampaignId=1,contextualLocation=country%3DUS%2Czip%3D19406", r.Header.Get("X-EBAY-C-ENDUSERCTX"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetItem(t *testing.T) {
|
func TestGetLegacyItem(t *testing.T) {
|
||||||
|
client, mux, teardown := setup(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
mux.HandleFunc("/buy/browse/v1/item/get_item_by_legacy_id", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, `{"itemId": "v1|%s|0"}`, r.URL.Query().Get("legacy_item_id"))
|
||||||
|
})
|
||||||
|
|
||||||
|
item, err := client.Buy.Browse.GetItemByLegacyID(context.Background(), "202117468662")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "v1|202117468662|0", item.ItemID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCompactItem(t *testing.T) {
|
||||||
client, mux, teardown := setup(t)
|
client, mux, teardown := setup(t)
|
||||||
defer teardown()
|
defer teardown()
|
||||||
|
|
||||||
@@ -35,3 +48,16 @@ func TestGetItem(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "COMPACT", item.ItemID)
|
assert.Equal(t, "COMPACT", item.ItemID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGettItem(t *testing.T) {
|
||||||
|
client, mux, teardown := setup(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
mux.HandleFunc("/buy/browse/v1/item/v1|202117468662|0", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, `{"itemId": "%s"}`, r.URL.Query().Get("fieldgroups"))
|
||||||
|
})
|
||||||
|
|
||||||
|
item, err := client.Buy.Browse.GetItem(context.Background(), "v1|202117468662|0")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "PRODUCT", item.ItemID)
|
||||||
|
}
|
||||||
|
|||||||
15
ebay.go
15
ebay.go
@@ -3,18 +3,17 @@ package ebay
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
baseURL = "https://api.ebay.com/"
|
baseURL = "https://api.ebay.com/"
|
||||||
sandboxBaseURL = "https://api.sandbox.ebay.com/"
|
sandboxBaseURL = "https://api.sandbox.ebay.com/"
|
||||||
|
|
||||||
headerEndUserCtx = "X-EBAY-C-ENDUSERCTX"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BuyAPI regroups the eBay Buy APIs.
|
// BuyAPI regroups the eBay Buy APIs.
|
||||||
@@ -22,6 +21,7 @@ const (
|
|||||||
// eBay API docs: https://developer.ebay.com/api-docs/buy/static/buy-landing.html
|
// eBay API docs: https://developer.ebay.com/api-docs/buy/static/buy-landing.html
|
||||||
type BuyAPI struct {
|
type BuyAPI struct {
|
||||||
Browse *BrowseService
|
Browse *BrowseService
|
||||||
|
Offer *OfferService
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client manages communication with the eBay API.
|
// Client manages communication with the eBay API.
|
||||||
@@ -63,6 +63,7 @@ func newClient(httpclient *http.Client, baseURL string) *Client {
|
|||||||
c := &Client{client: httpclient, baseURL: url}
|
c := &Client{client: httpclient, baseURL: url}
|
||||||
c.Buy = BuyAPI{
|
c.Buy = BuyAPI{
|
||||||
Browse: (*BrowseService)(&service{c}),
|
Browse: (*BrowseService)(&service{c}),
|
||||||
|
Offer: (*OfferService)(&service{c}),
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@@ -82,11 +83,11 @@ func (c *Client) NewRequest(method, url string, opts ...Opt) (*http.Request, err
|
|||||||
}
|
}
|
||||||
u, err := c.baseURL.Parse(url)
|
u, err := c.baseURL.Parse(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
req, err := http.NewRequest(method, u.String(), nil)
|
req, err := http.NewRequest(method, u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(req)
|
opt(req)
|
||||||
@@ -98,7 +99,7 @@ func (c *Client) NewRequest(method, url string, opts ...Opt) (*http.Request, err
|
|||||||
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) error {
|
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) error {
|
||||||
resp, err := c.client.Do(req.WithContext(ctx))
|
resp, err := c.client.Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if err := CheckResponse(resp); err != nil {
|
if err := CheckResponse(resp); err != nil {
|
||||||
@@ -107,7 +108,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) error
|
|||||||
if v == nil {
|
if v == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return json.NewDecoder(resp.Body).Decode(v)
|
return errors.WithStack(json.NewDecoder(resp.Body).Decode(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// An ErrorData reports one or more errors caused by an API request.
|
// An ErrorData reports one or more errors caused by an API request.
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -4,6 +4,7 @@ go 1.12
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0
|
golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -5,6 +5,8 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM
|
|||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|||||||
33
offer.go
Normal file
33
offer.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package ebay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OfferService handles communication with the Offer API
|
||||||
|
//
|
||||||
|
// eBay API docs: https://developer.ebay.com/api-docs/buy/offer/static/overview.html
|
||||||
|
type OfferService service
|
||||||
|
|
||||||
|
// Valid marketplace IDs
|
||||||
|
const (
|
||||||
|
BuyMarketplaceAustralia = "EBAY_AU"
|
||||||
|
BuyMarketplaceCanada = "EBAY_CA"
|
||||||
|
BuyMarketplaceGermany = "EBAY_DE"
|
||||||
|
BuyMarketplaceSpain = "EBAY_ES"
|
||||||
|
BuyMarketplaceFrance = "EBAY_FR"
|
||||||
|
BuyMarketplaceGreatBritain = "EBAY_GB"
|
||||||
|
BuyMarketplaceHongKong = "EBAY_HK"
|
||||||
|
BuyMarketplaceItalia = "EBAY_IT"
|
||||||
|
BuyMarketplaceUSA = "EBAY_US"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OptBuyMarketplace adds the header containing the marketplace id:
|
||||||
|
// https://developer.ebay.com/api-docs/buy/static/ref-marketplace-supported.html
|
||||||
|
//
|
||||||
|
// eBay API docs: https://developer.ebay.com/api-docs/buy/static/api-browse.html#Headers
|
||||||
|
func OptBuyMarketplace(marketplaceID string) func(*http.Request) {
|
||||||
|
return func(req *http.Request) {
|
||||||
|
req.Header.Set("X-EBAY-C-MARKETPLACE-ID", marketplaceID)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
offer_test.go
Normal file
15
offer_test.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package ebay_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jybp/ebay"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOptBuyMarketplace(t *testing.T) {
|
||||||
|
r, _ := http.NewRequest("", "", nil)
|
||||||
|
ebay.OptBuyMarketplace("EBAY_US")(r)
|
||||||
|
assert.Equal(t, "EBAY_US", r.Header.Get("X-EBAY-C-MARKETPLACE-ID"))
|
||||||
|
}
|
||||||
@@ -1,20 +1,25 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
"github.com/jybp/ebay"
|
"github.com/jybp/ebay"
|
||||||
"github.com/jybp/ebay/clientcredentials"
|
"github.com/jybp/ebay/clientcredentials"
|
||||||
)
|
)
|
||||||
|
|
||||||
var client *ebay.Client
|
var (
|
||||||
|
integration bool
|
||||||
|
client *ebay.Client
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
flag.BoolVar(&integration, "integration", false, "run integration tests")
|
||||||
clientID := os.Getenv("SANDBOX_CLIENT_ID")
|
clientID := os.Getenv("SANDBOX_CLIENT_ID")
|
||||||
clientSecret := os.Getenv("SANDBOX_CLIENT_SECRET")
|
clientSecret := os.Getenv("SANDBOX_CLIENT_SECRET")
|
||||||
if clientID == "" || clientSecret == "" {
|
if clientID == "" || clientSecret == "" {
|
||||||
@@ -29,29 +34,37 @@ func init() {
|
|||||||
client = ebay.NewSandboxClient(conf.Client(context.Background()))
|
client = ebay.NewSandboxClient(conf.Client(context.Background()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.ebay.com/my/api_test_tool?index=0&api=browse&call=item_summary_search__GET&variation=json
|
func TestAuction(t *testing.T) {
|
||||||
func TestAuthorization(t *testing.T) {
|
if !integration {
|
||||||
req, err := client.NewRequest("GET", "buy/browse/v1/item_summary/search?q=test")
|
t.SkipNow()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
into := map[string]interface{}{}
|
|
||||||
err = client.Do(context.Background(), req, &into)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if testing.Verbose() {
|
|
||||||
t.Log(into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://developer.ebay.com/my/api_test_tool?index=0&api=browse&call=item_summary_search__GET&variation=json
|
// Manually create an auction in the sandbox and copy/paste the url:
|
||||||
func TestGetItemByLegacyID(t *testing.T) {
|
const url = "https://www.sandbox.ebay.com/itm/110439278158"
|
||||||
it, err := client.Buy.Browse.GetItemByLegacyID(context.Background(), "110436963416")
|
|
||||||
|
ctx := context.Background()
|
||||||
|
lit, err := client.Buy.Browse.GetItemByLegacyID(ctx, url[strings.LastIndex(url, "/")+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatalf("%+v", err)
|
||||||
|
}
|
||||||
|
it, err := client.Buy.Browse.GetItem(ctx, lit.ItemID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%+v", err)
|
||||||
}
|
}
|
||||||
if testing.Verbose() {
|
if testing.Verbose() {
|
||||||
t.Logf("%+v", it)
|
t.Logf("item: %+v", it)
|
||||||
}
|
}
|
||||||
|
isAuction := false
|
||||||
|
for _, opt := range it.BuyingOptions {
|
||||||
|
if opt == ebay.BrowseBuyingOptionAuction {
|
||||||
|
isAuction = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !isAuction {
|
||||||
|
t.Fatalf("item %s is not an auction. BuyingOptions are: %+v", it.ItemID, it.BuyingOptions)
|
||||||
|
}
|
||||||
|
if time.Now().UTC().After(it.ItemEndDate) {
|
||||||
|
t.Fatalf("item %s end date has been reached. ItemEndDate is: %s", it.ItemID, it.ItemEndDate.String())
|
||||||
|
}
|
||||||
|
t.Logf("item %s UniqueBidderCount:%d minimumBidPrice: %+v currentPriceToBid: %+v", it.ItemID, it.UniqueBidderCount, it.MinimumPriceToBid, it.CurrentBidPrice)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user