From 62ce92d8126355ffaa97d2b52c8af6828f5a590a Mon Sep 17 00:00:00 2001
From: Dimitrij Denissenko
Date: Mon, 28 Oct 2019 11:37:04 +0000
Subject: [PATCH] New major release
---
.travis.yml | 10 +-
LICENSE | 24 +
README.md | 42 +-
audio.go | 48 +-
audio_test.go | 61 ++-
banner.go | 36 +-
banner_test.go | 17 +-
bid.go | 55 +-
bid_test.go | 11 +-
bidrequest.go | 51 +-
bidrequest_test.go | 40 +-
bidresponse.go | 13 +-
bidresponse_test.go | 17 +-
content.go | 54 +-
content_test.go | 10 +-
device.go | 64 +--
device_test.go | 19 +-
doc.go | 2 +-
go.mod | 15 +-
go.sum | 31 +-
impression.go | 36 +-
impression_test.go | 9 +-
inventory.go | 37 +-
inventory_test.go | 22 +-
native.go | 12 +-
native/request/asset.go | 2 +-
native/request/data.go | 3 +
native/request/image.go | 5 +-
native/request/request.go | 58 ++-
native/request/request_test.go | 8 +-
native/request/title.go | 1 +
native/request/video.go | 18 +-
native/response/asset.go | 2 +-
native/response/data.go | 1 +
native/response/image.go | 1 +
native/response/link.go | 1 +
native/response/response.go | 6 +-
native/response/response_test.go | 13 +-
native/response/title.go | 1 +
native/response/video.go | 1 +
native_test.go | 6 +-
numbers_test.go | 4 -
openrtb.go | 851 +++++++++++++++++++++++++------
openrtb_test.go | 3 +-
pmp.go | 13 +-
pmp_test.go | 13 +-
seatbid.go | 11 +-
seatbid_test.go | 4 +-
video.go | 62 +--
video_test.go | 63 ++-
50 files changed, 1196 insertions(+), 691 deletions(-)
create mode 100644 LICENSE
diff --git a/.travis.yml b/.travis.yml
index 55a9f71..b888a14 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,9 @@
language: go
go:
- - 1.10.x
- - 1.11.x
-install:
- - go get -t ./...
+ - 1.12.x
+ - 1.13.x
env:
- GO111MODULE=on
-
+cache:
+ directories:
+ - $GOPATH/pkg/mod
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f731b7e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2015 Black Square Media Ltd. All rights reserved.
+(The MIT License)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Some test examples were taken from:
+https://code.google.com/p/openrtb/wiki/OpenRTB_Examples
diff --git a/README.md b/README.md
index e127471..73cb6be 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,29 @@
-# Go OpenRTB v2.x
+# OpenRTB
[![Build Status](https://travis-ci.org/bsm/openrtb.svg?branch=master)](https://travis-ci.org/bsm/openrtb)
-OpenRTB implementation for Go
+OpenRTB structs and validations for Go.
## Requirements
-Requires Go 1.8+ for proper `json.RawMessage` marshalling.
+Requires Go 1.8+ for proper `json.RawMessage` marshaling.
## Installation
To install, use `go get`:
```shell
-go get github.com/bsm/openrtb
+go get github.com/bsm/openrtb/v3
```
## Usage
-Import the package:
-
```go
package main
import (
"log"
- "github.com/bsm/openrtb"
+ "github.com/bsm/openrtb/v3"
)
func main() {
@@ -36,38 +34,10 @@ func main() {
defer file.Close()
var req *openrtb.BidRequest
- err = json.NewDecoder(file).Decode(&req)
- if err != nil {
+ if err := json.NewDecoder(file).Decode(&req); err != nil {
log.Fatal(err)
}
log.Printf("%+v\n", req)
}
```
-
-## Licence
-
- Copyright (c) 2015 Black Square Media Ltd. All rights reserved.
- (The MIT License)
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- 'Software'), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- Some test examples were taken from:
- https://code.google.com/p/openrtb/wiki/OpenRTB_Examples
diff --git a/audio.go b/audio.go
index 4a64e5a..1c67131 100644
--- a/audio.go
+++ b/audio.go
@@ -7,38 +7,38 @@ import (
// Validation errors
var (
- ErrInvalidAudioNoMimes = errors.New("openrtb: audio has no mimes")
+ ErrInvalidAudioNoMIMEs = errors.New("openrtb: audio has no mimes")
)
-// The "audio" object must be included directly in the impression object
+// Audio object must be included directly in the impression object
type Audio struct {
- Mimes []string `json:"mimes"` // Content MIME types supported.
- MinDuration int `json:"minduration,omitempty"` // Minimum video ad duration in seconds
- MaxDuration int `json:"maxduration,omitempty"` // Maximum video ad duration in seconds
- Protocols []int `json:"protocols,omitempty"` // Video bid response protocols
- StartDelay int `json:"startdelay,omitempty"` // Indicates the start delay in seconds
- Sequence int `json:"sequence,omitempty"` // Default: 1
- BAttr []int `json:"battr,omitempty"` // Blocked creative attributes
- MaxExtended int `json:"maxextended,omitempty"` // Maximum extended video ad duration
- MinBitrate int `json:"minbitrate,omitempty"` // Minimum bit rate in Kbps
- MaxBitrate int `json:"maxbitrate,omitempty"` // Maximum bit rate in Kbps
- Delivery []int `json:"delivery,omitempty"` // List of supported delivery methods
- CompanionAd []Banner `json:"companionad,omitempty"`
- API []int `json:"api,omitempty"`
- CompanionType []int `json:"companiontype,omitempty"`
- MaxSequence int `json:"maxseq,omitempty"` // The maximumnumber of ads that canbe played in an ad pod.
- Feed int `json:"feed,omitempty"` // Type of audio feed.
- Stitched int `json:"stitched,omitempty"` // Indicates if the ad is stitched with audio content or delivered independently
- NVol int `json:"nvol,omitempty"` // Volume normalization mode.
- Ext json.RawMessage `json:"ext,omitempty"`
+ MIMEs []string `json:"mimes"` // Content MIME types supported.
+ MinDuration int `json:"minduration,omitempty"` // Minimum video ad duration in seconds
+ MaxDuration int `json:"maxduration,omitempty"` // Maximum video ad duration in seconds
+ Protocols []Protocol `json:"protocols,omitempty"` // Video bid response protocols
+ StartDelay StartDelay `json:"startdelay,omitempty"` // Indicates the start delay in seconds
+ Sequence int `json:"sequence,omitempty"` // Default: 1
+ BlockedAttrs []CreativeAttribute `json:"battr,omitempty"` // Blocked creative attributes
+ MaxExtended int `json:"maxextended,omitempty"` // Maximum extended video ad duration
+ MinBitrate int `json:"minbitrate,omitempty"` // Minimum bit rate in Kbps
+ MaxBitrate int `json:"maxbitrate,omitempty"` // Maximum bit rate in Kbps
+ Delivery []ContentDelivery `json:"delivery,omitempty"` // List of supported delivery methods
+ CompanionAds []Banner `json:"companionad,omitempty"`
+ APIs []APIFramework `json:"api,omitempty"`
+ CompanionTypes []CompanionType `json:"companiontype,omitempty"`
+ MaxSequence int `json:"maxseq,omitempty"` // The maximumnumber of ads that canbe played in an ad pod.
+ Feed FeedType `json:"feed,omitempty"` // Type of audio feed.
+ Stitched int `json:"stitched,omitempty"` // Indicates if the ad is stitched with audio content or delivered independently
+ VolumeNorm VolumeNorm `json:"nvol,omitempty"` // Volume normalization mode.
+ Ext json.RawMessage `json:"ext,omitempty"`
}
type jsonAudio Audio
-// Validates the object
+// Validate the object
func (a *Audio) Validate() error {
- if len(a.Mimes) == 0 {
- return ErrInvalidAudioNoMimes
+ if len(a.MIMEs) == 0 {
+ return ErrInvalidAudioNoMIMEs
}
return nil
}
diff --git a/audio_test.go b/audio_test.go
index 4a4937e..85e9dfd 100644
--- a/audio_test.go
+++ b/audio_test.go
@@ -9,50 +9,49 @@ var _ = Describe("Audio", func() {
var subject *Audio
BeforeEach(func() {
- err := fixture("audio", &subject)
- Expect(err).NotTo(HaveOccurred())
+ Expect(fixture("audio", &subject)).To(Succeed())
})
It("should parse correctly", func() {
Expect(subject).To(Equal(&Audio{
- Mimes: []string{
+ MIMEs: []string{
"audio/mp4",
},
- MinDuration: 5,
- MaxDuration: 30,
- Protocols: []int{AudioProtocolDAAST1, AudioProtocolDAAST1Wrapper},
- Sequence: 1,
- BAttr: []int{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert},
- MaxExtended: 30,
- MinBitrate: 300,
- MaxBitrate: 1500,
- Delivery: []int{ContentDeliveryProgressive},
- CompanionAd: []Banner{
- {W: 300, H: 250, ID: "1234567893-1", Pos: AdPosAboveFold, BAttr: []int{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}, ExpDir: []int{ExpDirRight, ExpDirDown}},
- {W: 728, H: 90, ID: "1234567893-2", Pos: AdPosAboveFold, BAttr: []int{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}},
+ MinDuration: 5,
+ MaxDuration: 30,
+ Protocols: []Protocol{ProtocolDAAST1, ProtocolDAAST1Wrapper},
+ Sequence: 1,
+ BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert},
+ MaxExtended: 30,
+ MinBitrate: 300,
+ MaxBitrate: 1500,
+ Delivery: []ContentDelivery{ContentDeliveryProgressive},
+ CompanionAds: []Banner{
+ {Width: 300, Height: 250, ID: "1234567893-1", Position: AdPositionAboveFold, BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}, ExpDirs: []ExpDir{ExpDirRight, ExpDirDown}},
+ {Width: 728, Height: 90, ID: "1234567893-2", Position: AdPositionAboveFold, BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}},
},
- API: []int{APIFrameworkVPAID1, APIFrameworkVPAID2},
- CompanionType: []int{VASTCompanionStatic, VASTCompanionHTML},
+ APIs: []APIFramework{APIFrameworkVPAID1, APIFrameworkVPAID2},
+ CompanionTypes: []CompanionType{CompanionTypeStatic, CompanionTypeHTML},
}))
})
It("should validate", func() {
Expect((&Audio{
- MinDuration: 5,
- MaxDuration: 30,
- Protocols: []int{AudioProtocolDAAST1, AudioProtocolDAAST1Wrapper},
- Sequence: 1,
- BAttr: []int{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert},
- MaxExtended: 30,
- MinBitrate: 300,
- MaxBitrate: 1500,
- Delivery: []int{ContentDeliveryProgressive},
- CompanionAd: []Banner{
- {W: 300, H: 250, ID: "1234567893-1", Pos: AdPosAboveFold, BAttr: []int{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}, ExpDir: []int{ExpDirRight, ExpDirDown}},
- {W: 728, H: 90, ID: "1234567893-2", Pos: AdPosAboveFold, BAttr: []int{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}},
+ MinDuration: 5,
+ MaxDuration: 30,
+ Protocols: []Protocol{ProtocolDAAST1, ProtocolDAAST1Wrapper},
+ Sequence: 1,
+ BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert},
+ MaxExtended: 30,
+ MinBitrate: 300,
+ MaxBitrate: 1500,
+ Delivery: []ContentDelivery{ContentDeliveryProgressive},
+ CompanionAds: []Banner{
+ {Width: 300, Height: 250, ID: "1234567893-1", Position: AdPositionAboveFold, BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}, ExpDirs: []ExpDir{ExpDirRight, ExpDirDown}},
+ {Width: 728, Height: 90, ID: "1234567893-2", Position: AdPositionAboveFold, BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated, CreativeAttributeWindowsDialogOrAlert}},
},
- CompanionType: []int{VASTCompanionStatic, VASTCompanionHTML},
- }).Validate()).To(Equal(ErrInvalidAudioNoMimes))
+ CompanionTypes: []CompanionType{CompanionTypeStatic, CompanionTypeHTML},
+ }).Validate()).To(Equal(ErrInvalidAudioNoMIMEs))
})
})
diff --git a/banner.go b/banner.go
index 5468626..0b8fc98 100644
--- a/banner.go
+++ b/banner.go
@@ -2,28 +2,28 @@ package openrtb
import "encoding/json"
-// The "banner" object must be included directly in the impression object if the impression offered
+// Banner object must be included directly in the impression object if the impression offered
// for auction is display or rich media, or it may be optionally embedded in the video object to
// describe the companion banners available for the linear or non-linear video ad. The banner
// object may include a unique identifier; this can be useful if these IDs can be leveraged in the
// VAST response to dictate placement of the companion creatives when multiple companion ad
// opportunities of the same size are available on a page.
type Banner struct {
- W int `json:"w,omitempty"` // Width
- H int `json:"h,omitempty"` // Height
- Format []Format `json:"format,omitempty"` //Array of format objects representing the banner sizes permitted.
- WMax int `json:"wmax,omitempty"` // Width maximum DEPRECATED
- HMax int `json:"hmax,omitempty"` // Height maximum DEPRECATED
- WMin int `json:"wmin,omitempty"` // Width minimum DEPRECATED
- HMin int `json:"hmin,omitempty"` // Height minimum DEPRECATED
- ID string `json:"id,omitempty"` // A unique identifier
- BType []int `json:"btype,omitempty"` // Blocked creative types
- BAttr []int `json:"battr,omitempty"` // Blocked creative attributes
- Pos int `json:"pos,omitempty"` // Ad Position
- Mimes []string `json:"mimes,omitempty"` // Whitelist of content MIME types supported
- TopFrame int `json:"topframe,omitempty"` // Default: 0 ("1": Delivered in top frame, "0": Elsewhere)
- ExpDir []int `json:"expdir,omitempty"` // Specify properties for an expandable ad
- Api []int `json:"api,omitempty"` // List of supported API frameworks
- Vcm int `json:"vcm,omitempty"` // Represents the relationship with video. 0 = concurrent, 1 = end-card
- Ext json.RawMessage `json:"ext,omitempty"`
+ Width int `json:"w,omitempty"` // Width
+ Height int `json:"h,omitempty"` // Height
+ Formats []Format `json:"format,omitempty"` // Array of format objects representing the banner sizes permitted.
+ WidthMax int `json:"wmax,omitempty"` // Width maximum DEPRECATED
+ HeightMax int `json:"hmax,omitempty"` // Height maximum DEPRECATED
+ WidthMin int `json:"wmin,omitempty"` // Width minimum DEPRECATED
+ HeightMin int `json:"hmin,omitempty"` // Height minimum DEPRECATED
+ ID string `json:"id,omitempty"` // A unique identifier
+ BlockedTypes []BannerType `json:"btype,omitempty"` // Blocked banner types
+ BlockedAttrs []CreativeAttribute `json:"battr,omitempty"` // Blocked creative attributes
+ Position AdPosition `json:"pos,omitempty"` // Ad Position
+ MIMEs []string `json:"mimes,omitempty"` // Whitelist of content MIME types supported
+ TopFrame int `json:"topframe,omitempty"` // Default: 0 ("1": Delivered in top frame, "0": Elsewhere)
+ ExpDirs []ExpDir `json:"expdir,omitempty"` // Specify properties for an expandable ad
+ APIs []APIFramework `json:"api,omitempty"` // List of supported API frameworks
+ VCM int `json:"vcm,omitempty"` // Represents the relationship with video. 0 = concurrent, 1 = end-card
+ Ext json.RawMessage `json:"ext,omitempty"`
}
diff --git a/banner_test.go b/banner_test.go
index f982d2b..26e3f0d 100644
--- a/banner_test.go
+++ b/banner_test.go
@@ -9,19 +9,18 @@ var _ = Describe("Banner", func() {
var subject *Banner
BeforeEach(func() {
- err := fixture("banner", &subject)
- Expect(err).NotTo(HaveOccurred())
+ Expect(fixture("banner", &subject)).To(Succeed())
})
It("should parse correctly", func() {
Expect(subject).To(Equal(&Banner{
- W: 728,
- H: 90,
- Pos: AdPosAboveFold,
- BType: []int{BannerTypeFrame},
- BAttr: []int{CreativeAttributeWindowsDialogOrAlert},
- Api: []int{APIFrameworkMRAID1},
- Vcm: 1,
+ Width: 728,
+ Height: 90,
+ Position: AdPositionAboveFold,
+ BlockedTypes: []BannerType{BannerTypeFrame},
+ BlockedAttrs: []CreativeAttribute{CreativeAttributeWindowsDialogOrAlert},
+ APIs: []APIFramework{APIFrameworkMRAID1},
+ VCM: 1,
}))
})
diff --git a/bid.go b/bid.go
index 18a98c8..f8a3a5c 100644
--- a/bid.go
+++ b/bid.go
@@ -11,6 +11,7 @@ var (
ErrInvalidBidNoImpID = errors.New("openrtb: bid is missing impression ID")
)
+// Bid object contains bid information.
// ID, ImpID and Price are required; all other optional.
// If the bidder wins the impression, the exchange calls notice URL (nurl)
// a) to inform the bidder of the win;
@@ -19,33 +20,33 @@ var (
// Cid can be used to block ads that were previously identified as inappropriate.
// Substitution macros may allow a bidder to use a static notice URL for all of its bids.
type Bid struct {
- ID string `json:"id"`
- ImpID string `json:"impid"` // Required string ID of the impression object to which this bid applies.
- Price float64 `json:"price"` // Bid price in CPM. Suggests using integer math for accounting to avoid rounding errors.
- AdID string `json:"adid,omitempty"` // References the ad to be served if the bid wins.
- NURL string `json:"nurl,omitempty"` // Win notice URL.
- BURL string `json:"burl,omitempty"` // Billing notice URL.
- LURL string `json:"lurl,omitempty"` // Loss notice URL.
- AdMarkup string `json:"adm,omitempty"` // Actual ad markup. XHTML if a response to a banner object, or VAST XML if a response to a video object.
- AdvDomain []string `json:"adomain,omitempty"` // Advertiser’s primary or top-level domain for advertiser checking; or multiple if imp rotating.
- Bundle string `json:"bundle,omitempty"` // A platform-specific application identifier intended to be unique to the app and independent of the exchange.
- IURL string `json:"iurl,omitempty"` // Sample image URL.
- CampaignID StringOrNumber `json:"cid,omitempty"` // Campaign ID that appears with the Ad markup.
- CreativeID string `json:"crid,omitempty"` // Creative ID for reporting content issues or defects. This could also be used as a reference to a creative ID that is posted with an exchange.
- Tactic string `json:"tactic,omitempty"` // Tactic ID to enable buyers to label bids for reporting to the exchange the tactic through which their bid was submitted.
- Cat []string `json:"cat,omitempty"` // IAB content categories of the creative. Refer to List 5.1
- Attr []int `json:"attr,omitempty"` // Array of creative attributes.
- API int `json:"api,omitempty"` // API required by the markup if applicable
- Protocol int `json:"protocol,omitempty"` // Video response protocol of the markup if applicable
- QAGMediaRating int `json:"qagmediarating,omitempty"` // Creative media rating per IQG guidelines.
- Language string `json:"language,omitempty"` // Language of the creative using ISO-639-1-alpha-2.
- DealID string `json:"dealid,omitempty"` // DealID extension of private marketplace deals
- H int `json:"h,omitempty"` // Height of the ad in pixels.
- W int `json:"w,omitempty"` // Width of the ad in pixels.
- WRatio int `json:"wratio,omitempty"` // Relative width of the creative when expressing size as a ratio.
- HRatio int `json:"hratio,omitempty"` // Relative height of the creative when expressing size as a ratio.
- Exp int `json:"exp,omitempty"` // Advisory as to the number of seconds the bidder is willing to wait between the auction and the actual impression.
- Ext json.RawMessage `json:"ext,omitempty"`
+ ID string `json:"id"`
+ ImpID string `json:"impid"` // Required string ID of the impression object to which this bid applies.
+ Price float64 `json:"price"` // Bid price in CPM. Suggests using integer math for accounting to avoid rounding errors.
+ AdID string `json:"adid,omitempty"` // References the ad to be served if the bid wins.
+ NoticeURL string `json:"nurl,omitempty"` // Win notice URL.
+ BillingURL string `json:"burl,omitempty"` // Billing notice URL.
+ LossURL string `json:"lurl,omitempty"` // Loss notice URL.
+ AdMarkup string `json:"adm,omitempty"` // Actual ad markup. XHTML if a response to a banner object, or VAST XML if a response to a video object.
+ AdvDomains []string `json:"adomain,omitempty"` // Advertiser’s primary or top-level domain for advertiser checking; or multiple if imp rotating.
+ Bundle string `json:"bundle,omitempty"` // A platform-specific application identifier intended to be unique to the app and independent of the exchange.
+ ImageURL string `json:"iurl,omitempty"` // Sample image URL.
+ CampaignID StringOrNumber `json:"cid,omitempty"` // Campaign ID that appears with the Ad markup.
+ CreativeID string `json:"crid,omitempty"` // Creative ID for reporting content issues or defects. This could also be used as a reference to a creative ID that is posted with an exchange.
+ Tactic string `json:"tactic,omitempty"` // Tactic ID to enable buyers to label bids for reporting to the exchange the tactic through which their bid was submitted.
+ Categories []ContentCategory `json:"cat,omitempty"` // IAB content categories of the creative. Refer to List 5.1
+ Attrs []CreativeAttribute `json:"attr,omitempty"` // Array of creative attributes.
+ API APIFramework `json:"api,omitempty"` // API required by the markup if applicable
+ Protocol Protocol `json:"protocol,omitempty"` // Video response protocol of the markup if applicable
+ MediaRating IQGRating `json:"qagmediarating,omitempty"` // Creative media rating per IQG guidelines.
+ Language string `json:"language,omitempty"` // Language of the creative using ISO-639-1-alpha-2.
+ DealID string `json:"dealid,omitempty"` // DealID extension of private marketplace deals
+ Width int `json:"w,omitempty"` // Width of the ad in pixels.
+ Height int `json:"h,omitempty"` // Height of the ad in pixels.
+ WidthRatio int `json:"wratio,omitempty"` // Relative width of the creative when expressing size as a ratio.
+ HeightRatio int `json:"hratio,omitempty"` // Relative height of the creative when expressing size as a ratio.
+ Exp int `json:"exp,omitempty"` // Advisory as to the number of seconds the bidder is willing to wait between the auction and the actual impression.
+ Ext json.RawMessage `json:"ext,omitempty"`
}
// Validate required attributes
diff --git a/bid_test.go b/bid_test.go
index 369d2bd..44899b3 100644
--- a/bid_test.go
+++ b/bid_test.go
@@ -9,8 +9,7 @@ var _ = Describe("Bid", func() {
var subject *Bid
BeforeEach(func() {
- err := fixture("bid", &subject)
- Expect(err).NotTo(HaveOccurred())
+ Expect(fixture("bid", &subject)).To(Succeed())
})
It("should parse correctly", func() {
@@ -19,14 +18,14 @@ var _ = Describe("Bid", func() {
ImpID: "1",
Price: 0.751371,
AdID: "52a5516d29e435137c6f6e74",
- NURL: "http://ads.com/win/112770_1386565997?won=${AUCTION_PRICE}",
+ NoticeURL: "http://ads.com/win/112770_1386565997?won=${AUCTION_PRICE}",
AdMarkup: "",
- AdvDomain: []string{"ads.com"},
- IURL: "http://ads.com/112770_1386565997.jpeg",
+ AdvDomains: []string{"ads.com"},
+ ImageURL: "http://ads.com/112770_1386565997.jpeg",
CampaignID: "52a5516d29e435137c6f6e74",
CreativeID: "52a5516d29e435137c6f6e74_1386565997",
DealID: "example_deal",
- Attr: []int{},
+ Attrs: []CreativeAttribute{},
}))
})
diff --git a/bidrequest.go b/bidrequest.go
index 41fbd0e..d8d6873 100644
--- a/bidrequest.go
+++ b/bidrequest.go
@@ -12,45 +12,44 @@ var (
ErrInvalidReqMultiInv = errors.New("openrtb: request has multiple inventory sources") // has site and app
)
-// The top-level bid request object contains a globally unique bid request or auction ID. This "id"
+// BidRequest is the top-level bid request object contains a globally unique bid request or auction ID. This "id"
// attribute is required as is at least one "imp" (i.e., impression) object. Other attributes are
// optional since an exchange may establish default values.
type BidRequest struct {
- ID string `json:"id"` // Unique ID of the bid request
- Imp []Impression `json:"imp,omitempty"`
- Site *Site `json:"site,omitempty"`
- App *App `json:"app,omitempty"`
- Device *Device `json:"device,omitempty"`
- User *User `json:"user,omitempty"`
- Test int `json:"test,omitempty"` // Indicator of test mode in which auctions are not billable, where 0 = live mode, 1 = test mode
- AuctionType int `json:"at"` // Auction type, where 1 = First Price, 2 = Second Price Plus. Exchange-specific auction types can be defined using values greater than 500.
- TMax int `json:"tmax,omitempty"` // Maximum amount of time in milliseconds to submit a bid
- WSeat []string `json:"wseat,omitempty"` // Array of buyer seats allowed to bid on this auction
- BSeat []string `json:"bseat,omitempty"` // Array of buyer seats blocked to bid on this auction
- WLang []string `json:"wlang,omitempty"` // Array of languages for creatives using ISO-639-1-alpha-2
- AllImps int `json:"allimps,omitempty"` // Flag to indicate whether exchange can verify that all impressions offered represent all of the impressions available in context, Default: 0
- Cur []string `json:"cur,omitempty"` // Array of allowed currencies
- Bcat []string `json:"bcat,omitempty"` // Blocked Advertiser Categories.
- BAdv []string `json:"badv,omitempty"` // Array of strings of blocked toplevel domains of advertisers
- BApp []string `json:"bapp,omitempty"` // Block list of applications by their platform-specific exchange-independent application identifiers. On Android, these should be bundle or package names (e.g., com.foo.mygame). On iOS, these are numeric IDs.
- Source *Source `json:"source,omitempty"` // A Source object that provides data about the inventory source and which entity makes the final decision
- Regs *Regulations `json:"regs,omitempty"`
- Ext json.RawMessage `json:"ext,omitempty"`
-
- Pmp *Pmp `json:"pmp,omitempty"` // DEPRECATED: kept for backwards compatibility
+ ID string `json:"id"` // Unique ID of the bid request
+ Impressions []Impression `json:"imp,omitempty"`
+ Site *Site `json:"site,omitempty"`
+ App *App `json:"app,omitempty"`
+ Device *Device `json:"device,omitempty"`
+ User *User `json:"user,omitempty"`
+ Test int `json:"test,omitempty"` // Indicator of test mode in which auctions are not billable, where 0 = live mode, 1 = test mode
+ AuctionType int `json:"at"` // Auction type, where 1 = First Price, 2 = Second Price Plus. Exchange-specific auction types can be defined using values greater than 500.
+ TimeMax int `json:"tmax,omitempty"` // Maximum amount of time in milliseconds to submit a bid
+ Seats []string `json:"wseat,omitempty"` // Array of buyer seats allowed to bid on this auction
+ BlockedSeats []string `json:"bseat,omitempty"` // Array of buyer seats blocked to bid on this auction
+ Languages []string `json:"wlang,omitempty"` // Array of languages for creatives using ISO-639-1-alpha-2
+ AllImpressions int `json:"allimps,omitempty"` // Flag to indicate whether exchange can verify that all impressions offered represent all of the impressions available in context, Default: 0
+ Currencies []string `json:"cur,omitempty"` // Array of allowed currencies
+ BlockedCategories []ContentCategory `json:"bcat,omitempty"` // Blocked Advertiser Categories.
+ BlockedAdvDomains []string `json:"badv,omitempty"` // Array of strings of blocked toplevel domains of advertisers
+ BlockedApps []string `json:"bapp,omitempty"` // Block list of applications by their platform-specific exchange-independent application identifiers. On Android, these should be bundle or package names (e.g., com.foo.mygame). On iOS, these are numeric IDs.
+ Source *Source `json:"source,omitempty"` // A Source object that provides data about the inventory source and which entity makes the final decision
+ Regulations *Regulations `json:"regs,omitempty"`
+ Ext json.RawMessage `json:"ext,omitempty"`
}
-// Validates the request
+// Validate the request
func (req *BidRequest) Validate() error {
if req.ID == "" {
return ErrInvalidReqNoID
- } else if len(req.Imp) == 0 {
+ } else if len(req.Impressions) == 0 {
return ErrInvalidReqNoImps
} else if req.Site != nil && req.App != nil {
return ErrInvalidReqMultiInv
}
- for _, imp := range req.Imp {
+ for i := range req.Impressions {
+ imp := req.Impressions[i]
if err := (&imp).Validate(); err != nil {
return err
}
diff --git a/bidrequest_test.go b/bidrequest_test.go
index 68dc085..88131c3 100644
--- a/bidrequest_test.go
+++ b/bidrequest_test.go
@@ -8,9 +8,9 @@ import (
var _ = Describe("BidRequest", func() {
var subject *BidRequest
privacyPolicy := 1
+
BeforeEach(func() {
- err := fixture("breq.banner", &subject)
- Expect(err).NotTo(HaveOccurred())
+ Expect(fixture("breq.banner", &subject)).To(Succeed())
})
It("should parse complex requests", func() {
@@ -25,11 +25,11 @@ var _ = Describe("BidRequest", func() {
It("should parse correctly", func() {
Expect(subject).To(Equal(&BidRequest{
ID: "1234534625254",
- Imp: []Impression{
+ Impressions: []Impression{
{
ID: "1",
Secure: 1,
- Banner: &Banner{W: 300, H: 250, Pos: AdPosAboveFold, BAttr: []int{CreativeAttributeUserInitiated}},
+ Banner: &Banner{Width: 300, Height: 250, Position: AdPositionAboveFold, BlockedAttrs: []CreativeAttribute{CreativeAttributeUserInitiated}},
},
},
Site: &Site{
@@ -37,42 +37,42 @@ var _ = Describe("BidRequest", func() {
ID: "234563",
Name: "Site ABCD",
Domain: "siteabcd.com",
- Cat: []string{"IAB2-1", "IAB2-2"},
+ Categories: []ContentCategory{ContentCategoryAutoParts, ContentCategoryAutoRepair},
Publisher: &Publisher{ID: "pub12345", Name: "Publisher A"},
PrivacyPolicy: &privacyPolicy,
Content: &Content{
Keywords: "keyword a,keyword b,keyword c",
},
},
- Page: "http://siteabcd.com/page.htm",
- Ref: "http://referringsite.com/referringpage.htm",
+ Page: "http://siteabcd.com/page.htm",
+ Referrer: "http://referringsite.com/referringpage.htm",
},
Device: &Device{
- UA: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16",
- IP: "64.124.253.1",
- OS: "OS X",
- JS: 1,
- FlashVer: "10.1",
+ UA: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16",
+ IP: "64.124.253.1",
+ OS: "OS X",
+ JS: 1,
+ FlashVersion: "10.1",
},
User: &User{
ID: "45asdf987656789adfad4678rew656789",
BuyerUID: "5df678asd8987656asdf78987654",
},
- Test: 1,
- AuctionType: 2,
- TMax: 120,
- BAdv: []string{"company1.com", "company2.com"},
+ Test: 1,
+ AuctionType: 2,
+ TimeMax: 120,
+ BlockedAdvDomains: []string{"company1.com", "company2.com"},
}))
})
It("should validate", func() {
Expect((&BidRequest{}).Validate()).To(Equal(ErrInvalidReqNoID))
Expect((&BidRequest{ID: "A"}).Validate()).To(Equal(ErrInvalidReqNoImps))
- Expect((&BidRequest{ID: "A", Imp: []Impression{{ID: "1"}}, Site: &Site{}, App: &App{}}).Validate()).To(Equal(ErrInvalidReqMultiInv))
+ Expect((&BidRequest{ID: "A", Impressions: []Impression{{ID: "1"}}, Site: &Site{}, App: &App{}}).Validate()).To(Equal(ErrInvalidReqMultiInv))
- Expect((&BidRequest{ID: "A", Imp: []Impression{{ID: "1", Banner: &Banner{}}}}).Validate()).NotTo(HaveOccurred())
- Expect((&BidRequest{ID: "A", Imp: []Impression{{ID: "1", Banner: &Banner{}}}, Site: &Site{}}).Validate()).NotTo(HaveOccurred())
- Expect((&BidRequest{ID: "A", Imp: []Impression{{ID: "1", Banner: &Banner{}}}, App: &App{}}).Validate()).NotTo(HaveOccurred())
+ Expect((&BidRequest{ID: "A", Impressions: []Impression{{ID: "1", Banner: &Banner{}}}}).Validate()).NotTo(HaveOccurred())
+ Expect((&BidRequest{ID: "A", Impressions: []Impression{{ID: "1", Banner: &Banner{}}}, Site: &Site{}}).Validate()).NotTo(HaveOccurred())
+ Expect((&BidRequest{ID: "A", Impressions: []Impression{{ID: "1", Banner: &Banner{}}}, App: &App{}}).Validate()).NotTo(HaveOccurred())
Expect(subject.Validate()).NotTo(HaveOccurred())
})
diff --git a/bidresponse.go b/bidresponse.go
index 31d07af..58dde72 100644
--- a/bidresponse.go
+++ b/bidresponse.go
@@ -11,17 +11,18 @@ var (
ErrInvalidRespNoSeatBids = errors.New("openrtb: response missing seatbids")
)
+// BidResponse is the bid response wrapper object.
// ID and at least one "seatbid” object is required, which contains a bid on at least one impression.
// Other attributes are optional since an exchange may establish default values.
// No-Bids on all impressions should be indicated as a HTTP 204 response.
// For no-bids on specific impressions, the bidder should omit these from the bid response.
type BidResponse struct {
ID string `json:"id"` // Reflection of the bid request ID for logging purposes
- SeatBid []SeatBid `json:"seatbid"` // Array of seatbid objects
+ SeatBids []SeatBid `json:"seatbid"` // Array of seatbid objects
BidID string `json:"bidid,omitempty"` // Optional response tracking ID for bidders
Currency string `json:"cur,omitempty"` // Bid currency
CustomData string `json:"customdata,omitempty"` // Encoded user features
- NBR int `json:"nbr,omitempty"` // Reason for not bidding, where 0 = unknown error, 1 = technical error, 2 = invalid request, 3 = known web spider, 4 = suspected Non-Human Traffic, 5 = cloud, data center, or proxy IP, 6 = unsupported device, 7 = blocked publisher or site, 8 = unmatched user
+ NBR NBR `json:"nbr,omitempty"` // Reason for not bidding, where 0 = unknown error, 1 = technical error, 2 = invalid request, 3 = known web spider, 4 = suspected Non-Human Traffic, 5 = cloud, data center, or proxy IP, 6 = unsupported device, 7 = blocked publisher or site, 8 = unmatched user
Ext json.RawMessage `json:"ext,omitempty"` // Custom specifications in JSon
}
@@ -29,15 +30,15 @@ type BidResponse struct {
func (res *BidResponse) Validate() error {
if res.ID == "" {
return ErrInvalidRespNoID
- } else if len(res.SeatBid) == 0 {
+ } else if len(res.SeatBids) == 0 {
return ErrInvalidRespNoSeatBids
}
- for _, sb := range res.SeatBid {
- if err := sb.Validate(); err != nil {
+ for i := range res.SeatBids {
+ sb := res.SeatBids[i]
+ if err := (&sb).Validate(); err != nil {
return err
}
}
-
return nil
}
diff --git a/bidresponse_test.go b/bidresponse_test.go
index 8f81f17..3b94222 100644
--- a/bidresponse_test.go
+++ b/bidresponse_test.go
@@ -9,15 +9,13 @@ var _ = Describe("BidResponse", func() {
var subject *BidResponse
BeforeEach(func() {
- err := fixture("bres.single", &subject)
- Expect(err).NotTo(HaveOccurred())
+ Expect(fixture("bres.single", &subject)).To(Succeed())
})
It("should parse complex responses", func() {
for _, kind := range []string{"multi", "pmp", "vast"} {
var req *BidResponse
- err := fixture("bres."+kind, &req)
- Expect(err).NotTo(HaveOccurred(), "for %s", kind)
+ Expect(fixture("bres."+kind, &req)).To(Succeed(), "for %s", kind)
Expect(req.Validate()).NotTo(HaveOccurred(), "for %s", kind)
}
})
@@ -25,20 +23,20 @@ var _ = Describe("BidResponse", func() {
It("should parse responses", func() {
Expect(subject).To(Equal(&BidResponse{
ID: "BID-4-ZIMP-4b309eae-504a-4252-a8a8-4c8ceee9791a",
- SeatBid: []SeatBid{
+ SeatBids: []SeatBid{
{
- Bid: []Bid{
+ Bids: []Bid{
{
ID: "32a69c6ba388f110487f9d1e63f77b22d86e916b",
ImpID: "32a69c6ba388f110487f9d1e63f77b22d86e916b",
Price: 0.065445,
AdID: "529833ce55314b19e8796116",
- NURL: "http://ads.com/win/529833ce55314b19e8796116?won=${auction_price}",
+ NoticeURL: "http://ads.com/win/529833ce55314b19e8796116?won=${auction_price}",
AdMarkup: "