Add tests and continue integration test

This commit is contained in:
JBP
2019-08-15 22:05:50 +02:00
parent a050a065b3
commit bc5c9ef1e3
9 changed files with 267 additions and 280 deletions

View File

@@ -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
View File

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

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View 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
View 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"))
}

View File

@@ -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)
} }