Skip to content
This repository was archived by the owner on Dec 22, 2022. It is now read-only.

Commit 89b12b5

Browse files
arneschulz1984RainerVolk4014Hendrik Isekehendrikiseke1979
authored
Add Adapter Orbidder (prebid#1275)
Co-authored-by: Volk, Rainer <[email protected]> Co-authored-by: RainerVolk4014 <[email protected]> Co-authored-by: rvolk <> Co-authored-by: Hendrik Iseke <[email protected]> Co-authored-by: hendrikiseke1979 <[email protected]>
1 parent 25afe77 commit 89b12b5

20 files changed

+939
-0
lines changed

adapters/orbidder/orbidder.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package orbidder
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"github.com/mxmCherry/openrtb"
7+
"github.com/prebid/prebid-server/adapters"
8+
"github.com/prebid/prebid-server/errortypes"
9+
"github.com/prebid/prebid-server/openrtb_ext"
10+
"net/http"
11+
)
12+
13+
type OrbidderAdapter struct {
14+
endpoint string
15+
}
16+
17+
// MakeRequests makes the HTTP requests which should be made to fetch bids from orbidder.
18+
func (rcv *OrbidderAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
19+
var errs []error
20+
var validImps []openrtb.Imp
21+
22+
// check if imps exists, if not return error and do send request to orbidder.
23+
if len(request.Imp) == 0 {
24+
return nil, []error{&errortypes.BadInput{
25+
Message: "No impressions in request",
26+
}}
27+
}
28+
29+
// validate imps
30+
for _, imp := range request.Imp {
31+
if err := preprocess(&imp); err != nil {
32+
errs = append(errs, err)
33+
continue
34+
}
35+
validImps = append(validImps, imp)
36+
}
37+
38+
if len(validImps) == 0 {
39+
return nil, errs
40+
}
41+
42+
//set imp array to only valid imps
43+
request.Imp = validImps
44+
45+
requestBodyJSON, err := json.Marshal(request)
46+
if err != nil {
47+
errs = append(errs, err)
48+
return nil, errs
49+
}
50+
51+
headers := http.Header{}
52+
headers.Add("Content-Type", "application/json;charset=utf-8")
53+
headers.Add("Accept", "application/json")
54+
55+
return []*adapters.RequestData{{
56+
Method: "POST",
57+
Uri: rcv.endpoint,
58+
Body: requestBodyJSON,
59+
Headers: headers,
60+
}}, errs
61+
}
62+
63+
func preprocess(imp *openrtb.Imp) error {
64+
var bidderExt adapters.ExtImpBidder
65+
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
66+
return &errortypes.BadInput{
67+
Message: err.Error(),
68+
}
69+
}
70+
71+
var orbidderExt openrtb_ext.ExtImpOrbidder
72+
if err := json.Unmarshal(bidderExt.Bidder, &orbidderExt); err != nil {
73+
return &errortypes.BadInput{
74+
Message: "Wrong orbidder bidder ext: " + err.Error(),
75+
}
76+
}
77+
78+
return nil
79+
}
80+
81+
// MakeBids unpacks server response into Bids.
82+
func (rcv OrbidderAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
83+
if response.StatusCode == http.StatusNoContent {
84+
return nil, nil
85+
}
86+
87+
if response.StatusCode >= http.StatusInternalServerError {
88+
return nil, []error{&errortypes.BadServerResponse{
89+
Message: fmt.Sprintf("Unexpected status code: %d. Dsp server internal error.", response.StatusCode),
90+
}}
91+
}
92+
93+
if response.StatusCode >= http.StatusBadRequest {
94+
return nil, []error{&errortypes.BadInput{
95+
Message: fmt.Sprintf("Unexpected status code: %d. Bad request to dsp.", response.StatusCode),
96+
}}
97+
}
98+
99+
if response.StatusCode != http.StatusOK {
100+
return nil, []error{&errortypes.BadServerResponse{
101+
Message: fmt.Sprintf("Unexpected status code: %d. Bad response from dsp.", response.StatusCode),
102+
}}
103+
}
104+
105+
var bidResp openrtb.BidResponse
106+
if err := json.Unmarshal(response.Body, &bidResp); err != nil {
107+
return nil, []error{err}
108+
}
109+
110+
bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
111+
112+
for _, seatBid := range bidResp.SeatBid {
113+
for _, bid := range seatBid.Bid {
114+
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
115+
Bid: &bid,
116+
BidType: openrtb_ext.BidTypeBanner,
117+
})
118+
}
119+
}
120+
return bidResponse, nil
121+
}
122+
123+
func NewOrbidderBidder(endpoint string) *OrbidderAdapter {
124+
return &OrbidderAdapter{
125+
endpoint: endpoint,
126+
}
127+
}

adapters/orbidder/orbidder_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package orbidder
2+
3+
import (
4+
"encoding/json"
5+
"github.com/prebid/prebid-server/adapters/adapterstest"
6+
"github.com/prebid/prebid-server/openrtb_ext"
7+
"github.com/stretchr/testify/assert"
8+
"testing"
9+
)
10+
11+
func TestUnmarshalOrbidderExtImp(t *testing.T) {
12+
ext := json.RawMessage(`{"accountId":"orbidder-test", "placementId":"center-banner", "bidfloor": 0.1}`)
13+
impExt := new(openrtb_ext.ExtImpOrbidder)
14+
15+
assert.NoError(t, json.Unmarshal(ext, impExt))
16+
assert.Equal(t, &openrtb_ext.ExtImpOrbidder{
17+
AccountId: "orbidder-test",
18+
PlacementId: "center-banner",
19+
BidFloor: 0.1,
20+
}, impExt)
21+
}
22+
23+
func TestJsonSamples(t *testing.T) {
24+
adapterstest.RunJSONBidderTest(t, "orbiddertest", NewOrbidderBidder("https://orbidder-test"))
25+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
"mockBidRequest": {
3+
"id": "test-request-id",
4+
"app": {
5+
"bundle": "com.prebid"
6+
},
7+
"device": {
8+
"ifa":"87857b31-8942-4646-ae80-ab9c95bf3fab"
9+
},
10+
"imp": [
11+
{
12+
"id": "test-imp-id",
13+
"banner": {
14+
"format": [
15+
{
16+
"w": 300,
17+
"h": 250
18+
}
19+
]
20+
},
21+
"ext": {
22+
"bidder": {
23+
"accountId": "orbidder-test",
24+
"placementId": "test-placement",
25+
"bidfloor": 0.1
26+
}
27+
}
28+
}
29+
]
30+
},
31+
"httpCalls": [
32+
{
33+
"expectedRequest": {
34+
"uri": "https://orbidder-test",
35+
"body": {
36+
"id": "test-request-id",
37+
"app": {
38+
"bundle": "com.prebid"
39+
},
40+
"device": {
41+
"ifa":"87857b31-8942-4646-ae80-ab9c95bf3fab"
42+
},
43+
"imp": [
44+
{
45+
"id": "test-imp-id",
46+
"banner": {
47+
"format": [
48+
{
49+
"w": 300,
50+
"h": 250
51+
}
52+
]
53+
},
54+
"ext": {
55+
"bidder": {
56+
"accountId": "orbidder-test",
57+
"placementId": "test-placement",
58+
"bidfloor": 0.1
59+
}
60+
}
61+
}
62+
]
63+
}
64+
},
65+
"mockResponse": {
66+
"status": 200,
67+
"body": {
68+
"id": "test-request-id",
69+
"seatbid": [
70+
{
71+
"seat": "seat-id",
72+
"bid": [
73+
{
74+
"id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
75+
"impid": "test-imp-id",
76+
"adid": "11110126",
77+
"price": 0.500000,
78+
"adm": "some-test-ad",
79+
"crid": "test-crid",
80+
"h": 250,
81+
"w": 300
82+
}
83+
]
84+
}
85+
],
86+
"cur": "EUR"
87+
}
88+
}
89+
}
90+
],
91+
"expectedBidResponses": [
92+
{
93+
"currency": "EUR",
94+
"bids": [
95+
{
96+
"bid": {
97+
"id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
98+
"impid": "test-imp-id",
99+
"adid": "11110126",
100+
"price": 0.5,
101+
"adm": "some-test-ad",
102+
"crid": "test-crid",
103+
"w": 300,
104+
"h": 250
105+
},
106+
"type": "banner"
107+
}
108+
]
109+
}
110+
]
111+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"accountId": "orbidder-test",
3+
"placementId": "center-banner",
4+
"bidfloor": 0.1
5+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"mockBidRequest": {
3+
"id": "test-request-id",
4+
"app": {
5+
"bundle": "com.prebid"
6+
},
7+
"device": {
8+
"ifa":"87857b31-8942-4646-ae80-ab9c95bf3fab"
9+
},
10+
"imp": [
11+
{
12+
"id": "test-imp-id",
13+
"banner": {
14+
"format": [
15+
{
16+
"w": 300,
17+
"h": 250
18+
}
19+
]
20+
},
21+
"ext": {
22+
"bidder": {
23+
"accountId": "orbidder-test",
24+
"placementId": "test-placement",
25+
"bidfloor": 0.1
26+
}
27+
}
28+
}
29+
]
30+
},
31+
"httpCalls": [
32+
{
33+
"expectedRequest": {
34+
"uri": "https://orbidder-test",
35+
"body": {
36+
"id": "test-request-id",
37+
"app": {
38+
"bundle": "com.prebid"
39+
},
40+
"device": {
41+
"ifa":"87857b31-8942-4646-ae80-ab9c95bf3fab"
42+
},
43+
"imp": [
44+
{
45+
"id": "test-imp-id",
46+
"banner": {
47+
"format": [
48+
{
49+
"w": 300,
50+
"h": 250
51+
}
52+
]
53+
},
54+
"ext": {
55+
"bidder": {
56+
"accountId": "orbidder-test",
57+
"placementId": "test-placement",
58+
"bidfloor": 0.1
59+
}
60+
}
61+
}
62+
]
63+
}
64+
},
65+
"mockResponse": {
66+
"status": 400,
67+
"body": {
68+
}
69+
}
70+
}
71+
],
72+
"expectedMakeBidsErrors": [
73+
{
74+
"value": "Unexpected status code: 400. Bad request to dsp.",
75+
"comparison": "literal"
76+
}
77+
]
78+
}

0 commit comments

Comments
 (0)