Skip to content
115 changes: 115 additions & 0 deletions adapters/revx/revx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package revx

import (
"fmt"
"net/http"

"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/errortypes"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/prebid/prebid-server/v3/util/jsonutil"
)

// RevXAdapter struct
type adapter struct {
endPoint string
}

// Builder builds a new instance of the RevX adapter.
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
return &adapter{
endPoint: config.Endpoint, // Default endpoint
}, nil
}

// MakeRequests handles the OpenRTB bid request and returns адаптер.RequestData
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
var errors []error

// Build headers
headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")

// Marshal request
reqJson, err := jsonutil.Marshal(request)
if err != nil {
return nil, []error{&errortypes.BadInput{Message: fmt.Sprintf("Failed to marshal request: %s", err)}} // skip append
}

requestData := &adapters.RequestData{
Method: http.MethodPost,
Uri: a.endPoint,
Body: reqJson,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}

return []*adapters.RequestData{requestData}, errors
}

// MakeBids handles the OpenRTB bid response.
func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if externalRequest == nil {
return nil, nil
}

// Handle specific status codes first
if adapters.IsResponseStatusCodeNoContent(response) {
return nil, nil
}

// For all other status codes
if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
return nil, []error{err}
}

// Proceed with normal parsing
var serverBidResponse openrtb2.BidResponse
if err := jsonutil.Unmarshal(response.Body, &serverBidResponse); err != nil {
return nil, []error{err}
}

var typedBids []*adapters.TypedBid
var errs []error
for _, sb := range serverBidResponse.SeatBid {
for i := range sb.Bid {
mediaType, err := getMediaTypeForImp(sb.Bid[i])
if err != nil {
errs = append(errs, err)
continue
}
typedBids = append(typedBids, &adapters.TypedBid{
Bid: &sb.Bid[i],
BidType: mediaType,
})
}
}

if len(typedBids) == 0 {
return nil, errs
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(typedBids))
bidResponse.Bids = typedBids
bidResponse.Currency = serverBidResponse.Cur

return bidResponse, errs
}

func getMediaTypeForImp(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
switch bid.MType {
case openrtb2.MarkupBanner:
return openrtb_ext.BidTypeBanner, nil
case openrtb2.MarkupVideo:
return openrtb_ext.BidTypeVideo, nil
case openrtb2.MarkupNative:
return openrtb_ext.BidTypeNative, nil
default:
return "", &errortypes.BadServerResponse{
Message: fmt.Sprintf("Unsupported mtype %d for bid %s", bid.MType, bid.ID),
}
}
}
35 changes: 35 additions & 0 deletions adapters/revx/revx_external_null_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package revx_test

import (
"testing"

"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/adapters/revx"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/stretchr/testify/assert"
)

func TestMakeBids_NilExternalRequest(t *testing.T) {
// Arrange
bidder, buildErr := revx.Builder(openrtb_ext.BidderRevX, config.Adapter{
Endpoint: "prebid-use.atomex.net/ag=PUB123",
}, config.Server{
ExternalUrl: "http://hosturl.com",
GvlID: 375,
DataCenter: "2",
})

var internalReq *openrtb2.BidRequest
var response *adapters.ResponseData
if buildErr != nil {
t.Logf("RevX Builder created successfully: %+v", bidder)
}
// Act
bidderResponse, errs := bidder.MakeBids(internalReq, nil, response)

// Assert
assert.Nil(t, bidderResponse, "Expected bidderResponse to be nil when externalRequest is nil")
assert.Nil(t, errs, "Expected errors to be nil when externalRequest is nil")
}
27 changes: 27 additions & 0 deletions adapters/revx/revx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package revx_test

import (
"testing"

"github.com/prebid/prebid-server/v3/adapters/adapterstest"
"github.com/prebid/prebid-server/v3/adapters/revx"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/openrtb_ext"
)

func TestJsonSamples(t *testing.T) {
bidder, buildErr := revx.Builder(openrtb_ext.BidderRevX, config.Adapter{
Endpoint: "prebid-use.atomex.net/ag=PUB123",
}, config.Server{
ExternalUrl: "http://hosturl.com",
GvlID: 375,
DataCenter: "2",
})

if buildErr != nil {

t.Logf("RevX Builder created successfully: %+v", bidder)
}

adapterstest.RunJSONBidderTest(t, "revxtest", bidder)
}
109 changes: 109 additions & 0 deletions adapters/revx/revxtest/exemplary/simple-app-banner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"mockBidRequest": {
"id": "test-request-id",
"site": {
"page": "https://good.site/url"
},
"imp": [
{
"id": "imp-id",
"banner": {
"format": [
{
"w": 111,
"h": 111
}
]
},
"ext": {
"bidder": {
"pubname": "PUB123"
}
}
}
]
},
"httpCalls": [
{
"expectedRequest": {
"uri": "prebid-use.atomex.net/ag=PUB123",

"body": {
"id": "test-request-id",
"site": {
"page": "https://good.site/url"
},
"imp": [
{
"id": "imp-id",
"banner": {
"format": [
{
"w": 111,
"h": 111
}
]
},
"ext": {
"bidder": {
"pubname": "PUB123"
}
}
}
]
},
"impIDs": [
"imp-id"
]
},
"mockResponse": {
"status": 200,
"body": {
"id": "test-request-id",
"seatbid": [
{
"seat": "interactiveoffers",
"bid": [
{
"id": "randomid",
"impid": "imp-id",
"price": 0.5,
"adid": "12345678",
"adm": "some-test-ad",
"cid": "987",
"crid": "12345678",
"h": 111,
"w": 111,
"mtype": 1
}
]
}
],
"cur": "USD"
}
}
}
],
"expectedBidResponses": [
{
"currency": "USD",
"bids": [
{
"bid": {
"id": "randomid",
"impid": "imp-id",
"price": 0.5,
"adm": "some-test-ad",
"adid": "12345678",
"cid": "987",
"crid": "12345678",
"w": 111,
"h": 111,
"mtype": 1
},
"type": "banner"
}
]
}
]
}
99 changes: 99 additions & 0 deletions adapters/revx/revxtest/exemplary/simple-app-native.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
"mockBidRequest": {
"id": "test-request-id",
"app": {
"publisher": {
"name": "PUB123"
}
},
"imp": [
{
"id": "imp-id",
"native": {
"request": "{\"native\":{\"ver\":\"1.2\",\"api\":[1],\"battr\":[1,3,9],\"assets\":[{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":50}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":200}},{\"id\":3,\"required\":0,\"data\":{\"type\":12}},{\"id\":4,\"required\":0,\"data\":{\"type\":1}}]}}"
},
"ext": {
"bidder": {
"pubname": "PUB123"
}
}
}
]
},
"httpCalls": [
{
"expectedRequest": {
"uri": "prebid-use.atomex.net/ag=PUB123",
"body": {
"id": "test-request-id",
"app": {
"publisher": {
"name": "PUB123"
}
},
"imp": [
{
"id": "imp-id",
"native": {
"request": "{\"native\":{\"ver\":\"1.2\",\"api\":[1],\"battr\":[1,3,9],\"assets\":[{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"id\":1,\"required\":1,\"img\":{\"type\":3,\"wmin\":100,\"hmin\":50}},{\"id\":2,\"required\":0,\"data\":{\"type\":2,\"len\":200}},{\"id\":3,\"required\":0,\"data\":{\"type\":12}},{\"id\":4,\"required\":0,\"data\":{\"type\":1}}]}}"
},
"ext": {
"bidder": {
"pubname": "PUB123"
}
}
}
]
},
"impIDs": [
"imp-id"
]
},
"mockResponse": {
"status": 200,
"body": {
"id": "test-request-id",
"seatbid": [
{
"seat": "interactiveoffers",
"bid": [
{
"id": "randomid",
"impid": "imp-id",
"price": 0.5,
"adid": "12345678",
"adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"title\":{\"text\":\"Test Title\"}},{\"id\":1,\"img\":{\"url\":\"http://some.image.url\",\"w\":100,\"h\":50}},{\"id\":2,\"data\":{\"type\":2,\"value\":\"Test Body\"}},{\"id\":3,\"data\":{\"type\":12,\"value\":\"Test Sponsored\"}},{\"id\":4,\"data\":{\"type\":1,\"value\":\"Test Display URL\"}}],\"link\":{\"url\":\"http://click.url\"},\"imptrackers\":[\"http://impression.url\"]}}",
"cid": "987",
"crid": "12345678",
"mtype": 4

}
]
}
],
"cur": "USD"
}
}
}
],
"expectedBidResponses": [
{
"currency": "USD",
"bids": [
{
"bid": {
"id": "randomid",
"impid": "imp-id",
"price": 0.5,
"adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"title\":{\"text\":\"Test Title\"}},{\"id\":1,\"img\":{\"url\":\"http://some.image.url\",\"w\":100,\"h\":50}},{\"id\":2,\"data\":{\"type\":2,\"value\":\"Test Body\"}},{\"id\":3,\"data\":{\"type\":12,\"value\":\"Test Sponsored\"}},{\"id\":4,\"data\":{\"type\":1,\"value\":\"Test Display URL\"}}],\"link\":{\"url\":\"http://click.url\"},\"imptrackers\":[\"http://impression.url\"]}}",
"adid": "12345678",
"cid": "987",
"crid": "12345678",
"mtype": 4
},
"type": "native"
}
]
}
]
}
Loading
Loading