diff --git a/README.md b/README.md index 32bc5f9..a039194 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GoDoc](https://godoc.org/gopkg.in/mxmCherry/openrtb.v2?status.svg)](https://godoc.org/gopkg.in/mxmCherry/openrtb.v2) -[OpenRTB](//github.com/openrtb/OpenRTB) [v2.3](//github.com/openrtb/OpenRTB/blob/master/OpenRTB-API-Specification-Version-2-3-FINAL.pdf) types for Go programming language (golang) +[OpenRTB](//github.com/openrtb/OpenRTB) [v2.3.1](//github.com/openrtb/OpenRTB/blob/master/OpenRTB-API-Specification-Version-2-3-1-FINAL.pdf) types for Go programming language (golang) **Warning!** Using [glide](https://github.com/Masterminds/glide) is recommended to vendor specific commit hash. @@ -31,7 +31,7 @@ Provide base for OpenRTB-related projects, focusing on: - Capitalized ID keys ## Types -- Key types should be chosen according to OpenRTB v2.3 specification (attribute types) +- Key types should be chosen according to OpenRTB v2.3.1 specification (attribute types) - Numeric types: - architecture-independent, e.g., ```int32``` instead of ```int``` - signed integral types should be used only when absolutely needed (value may contain negative numbers), unsigned integral types are preferred diff --git a/openrtb_test.go b/openrtb_test.go new file mode 100644 index 0000000..7d6f7c3 --- /dev/null +++ b/openrtb_test.go @@ -0,0 +1,78 @@ +package openrtb_test + +import ( + "encoding/json" + "io/ioutil" + "path/filepath" + "testing" + + "github.com/mxmCherry/openrtb" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +func TestOpenRTB(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "OpenRTB") +} + +// ---------------------------------------------------------------------------- + +var _ = DescribeTable( + "Marshalling", + func(filename string, subject interface{}) { + + expected, err := ioutil.ReadFile(filepath.Join("testdata", filename)) + Expect(err).NotTo(HaveOccurred()) + + Expect(json.Unmarshal(expected, subject)).To(Succeed()) + + actual, err := json.Marshal(subject) + Expect(err).NotTo(HaveOccurred()) + + Expect(actual).To(MatchJSON(expected)) + }, + Entry( + "Bid Request - Simple Banner", + "bid-request-simple-banner.json", + new(openrtb.BidRequest)), + Entry( + "Bid Request - Expandable Creative", + "bid-request-expandable-creative.json", + new(openrtb.BidRequest)), + Entry( + "Bid Request - Mobile", + "bid-request-mobile.json", + new(openrtb.BidRequest)), + Entry( + "Bid Request - Video", + "bid-request-video.json", + new(openrtb.BidRequest)), + Entry( + "Bid Request - PMP with Direct Deal", + "bid-request-pmp-with-direct-deal.json", + new(openrtb.BidRequest)), + Entry( + "Bid Request - Native Ad", + "bid-request-native-ad.json", + new(openrtb.BidRequest)), + + Entry( + "Bid Response - Ad Served on Win Notice", + "bid-response-ad-served-on-win-notice.json", + new(openrtb.BidResponse)), + Entry( + "Bid Response - VAST XML Document Returned Inline", + "bid-response-vast-xml-document-returned-inline.json", + new(openrtb.BidResponse)), + Entry( + "Bid Response - Direct Deal Ad Served on Win Notice", + "bid-response-direct-deal-ad-served-on-win-notice.json", + new(openrtb.BidResponse)), + Entry( + "Bid Response - Native Markup Returned Inline", + "bid-response-native-markup-returned-inline.json", + new(openrtb.BidResponse)), +) diff --git a/testdata/README.md b/testdata/README.md new file mode 100644 index 0000000..73042e9 --- /dev/null +++ b/testdata/README.md @@ -0,0 +1,5 @@ +# Testdata + +JSON examples copied from [OpenRTB](//github.com/openrtb/OpenRTB) [v2.3.1](//github.com/openrtb/OpenRTB/blob/master/OpenRTB-API-Specification-Version-2-3-1-FINAL.pdf) spec - section 6. Bid Request/Response Samples. + +Some empty/zero attributes (like `imp[i].banner.pos == 0`) were omited because of [encoding/json](//golang.org/pkg/encoding/json/) `omitempty` and [gomega.MatchJSON(...)](//onsi.github.io/gomega/#matchjsonjson-interface). diff --git a/testdata/bid-request-expandable-creative.json b/testdata/bid-request-expandable-creative.json new file mode 100644 index 0000000..71a2e16 --- /dev/null +++ b/testdata/bid-request-expandable-creative.json @@ -0,0 +1,51 @@ +{ + "id": "123456789316e6ede735f123ef6e32361bfc7b22", + "at": 2, + "cur": ["USD"], + "imp": [{ + "id": "1", + "bidfloor": 0.03, + "iframebuster": ["vendor1.com", "vendor2.com"], + "banner": { + "h": 250, + "w": 300, + "battr": [13], + "expdir": [2, 4] + } + }], + "site": { + "id": "102855", + "cat": ["IAB3-1"], + "domain": "www.foobar.com", + "page": "http://www.foobar.com/1234.html", + "publisher": { + "id": "8953", + "name": "foobar.com", + "cat": ["IAB3-1"], + "domain": "foobar.com" + } + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version / 5.1 .7 Safari / 534.57 .2 ", + "ip": "123.145.167.10" + }, + "user": { + "id": "55816b39711f9b5acf3b90e313ed29e51665623f", + "buyeruid": "545678765467876567898765678987654", + "data": [{ + "id": "6", + "name": "Data Provider 1", + "segment": [{ + "id": "12341318394918", + "name": "auto intenders" + }, { + "id": "1234131839491234", + "name": "auto enthusiasts" + }, { + "id": "23423424", + "name": "data-provider1-age", + "value": "30-40" + }] + }] + } +} diff --git a/testdata/bid-request-mobile.json b/testdata/bid-request-mobile.json new file mode 100644 index 0000000..686b33f --- /dev/null +++ b/testdata/bid-request-mobile.json @@ -0,0 +1,60 @@ +{ + "id": "IxexyLDIIk", + "at": 2, + "bcat": ["IAB25", "IAB7-39", "IAB8-18", "IAB8-5", "IAB9-9"], + "badv": ["apple.com", "go-text.me", "heywire.com"], + "imp": [{ + "id": "1", + "bidfloor": 0.5, + "tagid": "agltb3B1Yi1pbmNyDQsSBFNpdGUY7fD0FAw", + "banner": { + "w": 728, + "h": 90, + "pos": 1, + "btype": [4], + "battr": [14], + "api": [3] + } + }], + "app": { + "id": "agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA", + "name": "Yahoo Weather", + "cat": ["IAB15", "IAB15-10"], + "ver": "1.0.2", + "bundle": "com.yahoo.wxapp", + "storeurl": "https://itunes.apple.com/id628677149", + "publisher": { + "id": "agltb3B1Yi1pbmNyDAsSA0FwcBiJkfTUCV", + "name": "yahoo", + "domain": "www.yahoo.com" + } + }, + "device": { + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit / 534.46(KHTML, like Gecko) Version / 5.1 Mobile / 9 A334 Safari / 7534.48 .3 ", + "ip": "123.145.167.189", + "ifa": "AA000DFE74168477C70D291f574D344790E0BB11", + "carrier": "VERIZON", + "language": "en", + "make": "Apple", + "model": "iPhone", + "os": "iOS", + "osv": "6.1", + "js": 1, + "connectiontype": 3, + "devicetype": 1, + "geo": { + "lat": 35.012345, + "lon": -115.12345, + "country": "USA", + "metro": "803", + "region": "CA", + "city": "Los Angeles", + "zip": "90049" + } + }, + "user": { + "id": "ffffffd5135596709273b3a1a07e466ea2bf4fff", + "yob": 1984, + "gender": "M" + } +} diff --git a/testdata/bid-request-native-ad.json b/testdata/bid-request-native-ad.json new file mode 100644 index 0000000..cf95c72 --- /dev/null +++ b/testdata/bid-request-native-ad.json @@ -0,0 +1,34 @@ +{ + "id": "80ce30c53c16e6ede735f123ef6e32361bfc7b22", + "at": 1, + "cur": ["USD"], + "imp": [{ + "id": "1", + "bidfloor": 0.03, + "native": { + "request": "...Native Spec request as an encoded string...", + "ver": "1.0", + "api": [3], + "battr": [13, 14] + } + }], + "site": { + "id": "102855", + "cat": ["IAB3-1"], + "domain": "www.foobar.com", + "page": "http://www.foobar.com/1234.html ", + "publisher": { + "id": "8953", + "name": "foobar.com", + "cat": ["IAB3-1"], + "domain": "foobar.com" + } + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version / 5.1 .7 Safari / 534.57 .2 ", + "ip": "123.145.167.10" + }, + "user": { + "id": "55816b39711f9b5acf3b90e313ed29e51665623f" + } +} diff --git a/testdata/bid-request-pmp-with-direct-deal.json b/testdata/bid-request-pmp-with-direct-deal.json new file mode 100644 index 0000000..676d4bf --- /dev/null +++ b/testdata/bid-request-pmp-with-direct-deal.json @@ -0,0 +1,46 @@ +{ + "id": "80ce30c53c16e6ede735f123ef6e32361bfc7b22", + "at": 1, + "cur": ["USD"], + "imp": [{ + "id": "1", + "bidfloor": 0.03, + "banner": { + "h": 250, + "w": 300 + }, + "pmp": { + "private_auction": 1, + "deals": [{ + "id": "AB-Agency1-0001", + "at": 1, + "bidfloor": 2.5, + "wseat": ["Agency1"] + }, { + "id": "XY-Agency2-0001", + "at": 2, + "bidfloor": 2, + "wseat": ["Agency2"] + }] + } + }], + "site": { + "id": "102855", + "domain": "www.foobar.com", + "cat": ["IAB3-1"], + "page": "http://www.foobar.com/1234.html", + "publisher": { + "id": "8953", + "name": "foobar.com", + "cat": ["IAB3-1"], + "domain": "foobar.com" + } + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version / 5.1 .7 Safari / 534.57 .2 ", + "ip": "123.145.167.10" + }, + "user": { + "id": "55816b39711f9b5acf3b90e313ed29e51665623f" + } +} diff --git a/testdata/bid-request-simple-banner.json b/testdata/bid-request-simple-banner.json new file mode 100644 index 0000000..18b4129 --- /dev/null +++ b/testdata/bid-request-simple-banner.json @@ -0,0 +1,32 @@ +{ + "id": "80ce30c53c16e6ede735f123ef6e32361bfc7b22", + "at": 1, + "cur": ["USD"], + "imp": [{ + "id": "1", + "bidfloor": 0.03, + "banner": { + "h": 250, + "w": 300 + } + }], + "site": { + "id": "102855", + "cat": ["IAB3-1"], + "domain": "www.foobar.com", + "page": "http://www.foobar.com/1234.html ", + "publisher": { + "id": "8953", + "name": "foobar.com", + "cat": ["IAB3-1"], + "domain": "foobar.com" + } + }, + "device": { + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version / 5.1 .7 Safari / 534.57 .2 ", + "ip": "123.145.167.10" + }, + "user": { + "id": "55816b39711f9b5acf3b90e313ed29e51665623f" + } +} diff --git a/testdata/bid-request-video.json b/testdata/bid-request-video.json new file mode 100644 index 0000000..9ae9023 --- /dev/null +++ b/testdata/bid-request-video.json @@ -0,0 +1,91 @@ +{ + "id": "1234567893", + "at": 2, + "tmax": 120, + "imp": [{ + "id": "1", + "bidfloor": 0.03, + "video": { + "w": 640, + "h": 480, + "pos": 1, + "minduration": 5, + "maxduration": 30, + "maxextended": 30, + "minbitrate": 300, + "maxbitrate": 1500, + "api": [1, 2], + "protocols": [2, 3], + "mimes": [ + "video/x-flv", + "video/mp4", + "application/x-shockwave-flash", + "application/javascript" + ], + "linearity": 1, + "boxingallowed": 1, + "playbackmethod": [1, 3], + "delivery": [2], + "battr": [13, 14], + "companionad": [{ + "id": "1234567893-1", + "w": 300, + "h": 250, + "pos": 1, + "battr": [13, 14], + "expdir": [2, 4] + }, { + "id": "1234567893-2", + "w": 728, + "h": 90, + "pos": 1, + "battr": [13, 14] + }], + "companiontype": [1, 2] + } + }], + "site": { + "id": "1345135123", + "name": "Site ABCD", + "domain": "siteabcd.com", + "cat": ["IAB2-1", "IAB2-2"], + "page": "http://siteabcd.com/page.htm", + "ref": "http://referringsite.com/referringpage.htm", + "privacypolicy": 1, + "publisher": { + "id": "pub12345", + "name": "Publisher A" + }, + "content": { + "id": "1234567", + "series": "All About Cars", + "season": "2", + "episode": 23, + "title": "Car Show", + "cat": ["IAB2-2"], + "keywords": "keyword-a,keyword-b,keyword-c" + } + }, + "device": { + "ip": "64.124.253.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 ", + "os": "OS X", + "flashver": "10.1", + "js": 1 + }, + "user": { + "id": "456789876567897654678987656789", + "buyeruid": "545678765467876567898765678987654", + "data": [{ + "id": "6", + "name": "Data Provider 1", + "segment": [{ + "id": "12341318394918", + "name": "auto intenders" + }, { + "id": "1234131839491234", + "name": "auto enthusiasts" + }] + }] + } +} diff --git a/testdata/bid-response-ad-served-on-win-notice.json b/testdata/bid-response-ad-served-on-win-notice.json new file mode 100644 index 0000000..927050f --- /dev/null +++ b/testdata/bid-response-ad-served-on-win-notice.json @@ -0,0 +1,19 @@ +{ + "id": "1234567890", + "bidid": "abc1123", + "cur": "USD", + "seatbid": [{ + "seat": "512", + "bid": [{ + "id": "1", + "impid": "102", + "price": 9.43, + "nurl": "http://adserver.com/winnotice?impid=102", + "iurl": "http://adserver.com/pathtosampleimage", + "adomain": ["advertiserdomain.com"], + "cid": "campaign111", + "crid": "creative112", + "attr": [1, 2, 3, 4, 5, 6, 7, 12] + }] + }] +} diff --git a/testdata/bid-response-direct-deal-ad-served-on-win-notice.json b/testdata/bid-response-direct-deal-ad-served-on-win-notice.json new file mode 100644 index 0000000..ea27a80 --- /dev/null +++ b/testdata/bid-response-direct-deal-ad-served-on-win-notice.json @@ -0,0 +1,21 @@ +{ + "id": "1234567890", + "bidid": "abc1123", + "cur": "USD", + "seatbid": [{ + "seat": "512", + "bid": [{ + "id": "1", + "impid": "102", + "price": 5.00, + "dealid": "ABC-1234-6789", + "nurl": "http: //adserver.com/winnotice?impid=102", + "adomain": ["advertiserdomain.com"], + "iurl": "http: //adserver.com/pathtosampleimage", + "cid": "campaign111", + "crid": "creative112", + "adid": "314", + "attr": [1, 2, 3, 4] + }] + }] +} diff --git a/testdata/bid-response-native-markup-returned-inline.json b/testdata/bid-response-native-markup-returned-inline.json new file mode 100644 index 0000000..683bb2f --- /dev/null +++ b/testdata/bid-response-native-markup-returned-inline.json @@ -0,0 +1,12 @@ +{ + "id": "123", + "seatbid": [{ + "bid": [{ + "id": "12345", + "impid": "2", + "price": 3.00, + "nurl": "http://example.com/winnoticeurl", + "adm": "...Native Spec response as an encoded string..." + }] + }] +} diff --git a/testdata/bid-response-vast-xml-document-returned-inline.json b/testdata/bid-response-vast-xml-document-returned-inline.json new file mode 100644 index 0000000..070c303 --- /dev/null +++ b/testdata/bid-response-vast-xml-document-returned-inline.json @@ -0,0 +1,12 @@ +{ + "id": "123", + "seatbid": [{ + "bid": [{ + "id": "12345", + "impid": "2", + "price": 3.00, + "nurl": "http://example.com/winnoticeurl", + "adm": "%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0A%3CVAST%20version%3D%222.0%22%3E%0A%20%20%20%20%3CAd%20id%3D%2212345%22%3E%0A%20%20%20%20%20%20%20%20%3CInLine%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CAdSystem%20version%3D%221.0%22%3ESpotXchange%3C%2FAdSystem%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CAdTitle%3E%3C!%5BCDATA%5BSample%20VAST%5D%5D%3E%3C%2FAdTitle%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CImpression%3Ehttp%3A%2F%2Fsample.com%3C%2FImpression%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CDescription%3E%3C!%5BCDATA%5BA%20sample%20VAST%20feed%5D%5D%3E%3C%2FDescription%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CCreatives%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CCreative%20sequence%3D%221%22%20id%3D%221%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CLinear%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CDuration%3E00%3A00%3A30%3C%2FDuration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CTrackingEvents%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FTrackingEvents%3E%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CVideoClicks%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CClickThrough%3E%3C!%5BCDATA%5Bhttp%3A%2F%2Fsample.com%2Fopenrtbtest%5D%5D%3E%3C%2FClickThrough%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FVideoClicks%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CMediaFiles%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CMediaFile%20delivery%3D%22progressive%22%20bitrate%3D%22256%22%20width%3D%22640%22%20height%3D%22480%22%20type%3D%22video%2Fmp4%22%3E%3C!%5BCDATA%5Bhttp%3A%2F%2Fsample.com%2Fvideo.mp4%5D%5D%3E%3C%2FMediaFile%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FMediaFiles%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FLinear%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FCreative%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FCreatives%3E%0A%20%20%20%20%20%20%20%20%3C%2FInLine%3E%0A%20%20%20%20%3C%2FAd%3E%0A%3C%2FVAST%3E" + }] + }] +} diff --git a/user.go b/user.go index e41b932..a8119c7 100644 --- a/user.go +++ b/user.go @@ -17,6 +17,7 @@ type User struct { // buyerid is recommended. ID string `json:"id,omitempty"` + // DEPRECATED // Attribute: // buyerid // Type: @@ -24,8 +25,21 @@ type User struct { // Description: // Buyer-specific ID for the user as mapped by the exchange for // the buyer. At least one of buyerid or id is recommended. + // Dev note: + // Seems to be a mistype in OpenRTB 2.3 spec - it contains examples + // with "buyeruid" (not "buyerid"). + // OpenRTB 2.3.1 uses "buyeruid" only. BuyerID string `json:"buyerid,omitempty"` + // Attribute: + // buyeruid + // Type: + // string; recommended + // Description: + // Buyer-specific ID for the user as mapped by the exchange for + // the buyer. At least one of buyeruid or id is recommended. + BuyerUID string `json:"buyeruid,omitempty"` + // Attribute: // yob // Type: