Skip to content

Commit

Permalink
New Adapter: FeedAd (prebid#4104)
Browse files Browse the repository at this point in the history
  • Loading branch information
andwun authored Jan 30, 2025
1 parent 502a438 commit a266557
Show file tree
Hide file tree
Showing 15 changed files with 1,350 additions and 0 deletions.
93 changes: 93 additions & 0 deletions adapters/feedad/feedad.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package feedad

import (
"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/openrtb_ext"
"github.com/prebid/prebid-server/v3/util/jsonutil"
)

const feedAdAdapterVersion = "1.0.0"

func getHeaders(request *openrtb2.BidRequest) http.Header {
headers := http.Header{}
headers.Add("Accept", "application/json")
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("X-FA-PBS-Adapter-Version", feedAdAdapterVersion)
headers.Add("X-Openrtb-Version", "2.5")

if request.Device != nil {
if len(request.Device.IPv6) > 0 {
headers.Add("X-Forwarded-For", request.Device.IPv6)
}

if len(request.Device.IP) > 0 {
headers.Add("X-Forwarded-For", request.Device.IP)
}
}

return headers
}

type adapter struct {
endpoint string
}

func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if adapters.IsResponseStatusCodeNoContent(responseData) {
return nil, nil
}

if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
return nil, []error{err}
}

var response openrtb2.BidResponse
err := jsonutil.Unmarshal(responseData.Body, &response)
if err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp))
bidResponse.Currency = response.Cur

for _, seatBid := range response.SeatBid {
for i := range seatBid.Bid {
bidResponse.Bids = append(
bidResponse.Bids,
&adapters.TypedBid{
Bid: &seatBid.Bid[i],
BidType: openrtb_ext.BidTypeBanner,
},
)
}
}

return bidResponse, nil
}

func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
requestBody, err := jsonutil.Marshal(request)
if err != nil {
return nil, []error{err}
}

requestData := &adapters.RequestData{
Method: http.MethodPost,
Uri: a.endpoint,
Body: requestBody,
Headers: getHeaders(request),
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}
return []*adapters.RequestData{requestData}, nil
}

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
bidder := &adapter{
endpoint: config.Endpoint,
}
return bidder, nil
}
25 changes: 25 additions & 0 deletions adapters/feedad/feedad_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package feedad

import (
"testing"

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

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(
openrtb_ext.BidderFeedAd,
config.Adapter{
Endpoint: "https://example.com/1/prebid/requests",
},
config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"},
)

if buildErr != nil {
t.Fatalf("Builder returned unexpected error: %v", buildErr)
}

adapterstest.RunJSONBidderTest(t, "feedadtest", bidder)
}
161 changes: 161 additions & 0 deletions adapters/feedad/feedadtest/exemplary/banner-app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
{
"mockBidRequest": {
"id": "some-request-id",
"device": {
"ua": "test-user-agent",
"ip": "123.123.123.123",
"language": "en",
"dnt": 0
},
"tmax": 1000,
"user": {
"buyeruid": "awesome-user"
},
"app": {
"publisher": {
"id": "123456789"
},
"cat": [
"IAB22-1"
],
"bundle": "com.app.awesome",
"name": "Awesome App",
"domain": "awesomeapp.com",
"id": "123456789"
},
"imp": [
{
"id": "1",
"tagid": "ogTAGID",
"banner": {
"w": 320,
"h": 50
},
"ext": {
"bidder": {
"clientToken": "some-client-token",
"placementId": "some-placement-id"
}
}
}
]
},
"httpCalls": [
{
"expectedRequest": {
"headers": {
"Accept": [
"application/json"
],
"Content-Type": [
"application/json;charset=utf-8"
],
"X-Fa-Pbs-Adapter-Version": [
"1.0.0"
],
"X-Forwarded-For": [
"123.123.123.123"
],
"X-Openrtb-Version": [
"2.5"
]
},
"uri": "https://example.com/1/prebid/requests",
"body": {
"id": "some-request-id",
"device": {
"ua": "test-user-agent",
"ip": "123.123.123.123",
"language": "en",
"dnt": 0
},
"imp": [
{
"id": "1",
"banner": {
"w": 320,
"h": 50
},
"ext": {
"bidder": {
"clientToken": "some-client-token",
"placementId": "some-placement-id"
}
},
"tagid": "ogTAGID"
}
],
"app": {
"id": "123456789",
"name": "Awesome App",
"bundle": "com.app.awesome",
"domain": "awesomeapp.com",
"cat": [
"IAB22-1"
],
"publisher": {
"id": "123456789"
}
},
"user": {
"buyeruid": "awesome-user"
},
"tmax": 1000
},
"impIDs": [
"1"
]
},
"mockResponse": {
"status": 200,
"body": {
"id": "awesome-resp-id",
"seatbid": [
{
"bid": [
{
"id": "a3ae1b4e2fc24a4fb45540082e98e161",
"impid": "1",
"price": 3.5,
"adm": "awesome-markup",
"adomain": [
"awesome.com"
],
"crid": "20",
"w": 320,
"h": 50,
"mtype": 1
}
],
"type": "banner",
"seat": "escalax"
}
],
"cur": "USD"
}
}
}
],
"expectedBidResponses": [
{
"bids": [
{
"bid": {
"id": "a3ae1b4e2fc24a4fb45540082e98e161",
"impid": "1",
"price": 3.5,
"adm": "awesome-markup",
"adomain": [
"awesome.com"
],
"crid": "20",
"w": 320,
"h": 50,
"mtype": 1
},
"type": "banner"
}
]
}
]
}
Loading

0 comments on commit a266557

Please sign in to comment.