github.com/prebid/prebid-server/v2@v2.18.0/adapters/onetag/onetag.go (about) 1 package onetag 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "text/template" 8 9 "github.com/prebid/openrtb/v20/openrtb2" 10 "github.com/prebid/prebid-server/v2/adapters" 11 "github.com/prebid/prebid-server/v2/config" 12 "github.com/prebid/prebid-server/v2/errortypes" 13 "github.com/prebid/prebid-server/v2/macros" 14 "github.com/prebid/prebid-server/v2/openrtb_ext" 15 ) 16 17 type adapter struct { 18 endpointTemplate *template.Template 19 } 20 21 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 22 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 23 if err != nil { 24 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 25 } 26 27 bidder := &adapter{ 28 endpointTemplate: template, 29 } 30 31 return bidder, nil 32 } 33 34 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 35 pubID := "" 36 for idx, imp := range request.Imp { 37 onetagExt, err := getImpressionExt(imp) 38 if err != nil { 39 return nil, []error{err} 40 } 41 if onetagExt.PubId != "" { 42 if pubID == "" { 43 pubID = onetagExt.PubId 44 } else if pubID != onetagExt.PubId { 45 return nil, []error{&errortypes.BadInput{ 46 Message: "There must be only one publisher ID", 47 }} 48 } 49 } else { 50 return nil, []error{&errortypes.BadInput{ 51 Message: "The publisher ID must not be empty", 52 }} 53 } 54 request.Imp[idx].Ext = onetagExt.Ext 55 } 56 57 url, err := a.buildEndpointURL(pubID) 58 if err != nil { 59 return nil, []error{err} 60 } 61 62 requestJSON, err := json.Marshal(request) 63 if err != nil { 64 return nil, []error{err} 65 } 66 67 requestData := &adapters.RequestData{ 68 Method: "POST", 69 Uri: url, 70 Body: requestJSON, 71 ImpIDs: openrtb_ext.GetImpIDs(request.Imp), 72 } 73 74 return []*adapters.RequestData{requestData}, nil 75 } 76 77 func getImpressionExt(imp openrtb2.Imp) (*openrtb_ext.ExtImpOnetag, error) { 78 var bidderExt adapters.ExtImpBidder 79 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 80 return nil, &errortypes.BadInput{ 81 Message: "Bidder extension not provided or can't be unmarshalled", 82 } 83 } 84 85 var onetagExt openrtb_ext.ExtImpOnetag 86 if err := json.Unmarshal(bidderExt.Bidder, &onetagExt); err != nil { 87 return nil, &errortypes.BadInput{ 88 Message: "Error while unmarshaling bidder extension", 89 } 90 } 91 92 return &onetagExt, nil 93 } 94 95 func (a *adapter) buildEndpointURL(pubID string) (string, error) { 96 endpointParams := macros.EndpointTemplateParams{PublisherID: pubID} 97 return macros.ResolveMacros(a.endpointTemplate, endpointParams) 98 } 99 100 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 101 if responseData.StatusCode == http.StatusNoContent { 102 return nil, nil 103 } 104 105 if responseData.StatusCode != http.StatusOK { 106 err := &errortypes.BadServerResponse{ 107 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), 108 } 109 return nil, []error{err} 110 } 111 112 var response openrtb2.BidResponse 113 if err := json.Unmarshal(responseData.Body, &response); err != nil { 114 return nil, []error{err} 115 } 116 117 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) 118 bidResponse.Currency = response.Cur 119 for _, seatBid := range response.SeatBid { 120 for _, bid := range seatBid.Bid { 121 bidMediaType, err := getMediaTypeForBid(request.Imp, bid) 122 if err != nil { 123 return nil, []error{err} 124 } 125 b := &adapters.TypedBid{ 126 Bid: &bid, 127 BidType: bidMediaType, 128 } 129 bidResponse.Bids = append(bidResponse.Bids, b) 130 } 131 } 132 return bidResponse, nil 133 } 134 135 func getMediaTypeForBid(impressions []openrtb2.Imp, bid openrtb2.Bid) (openrtb_ext.BidType, error) { 136 for _, impression := range impressions { 137 if impression.ID == bid.ImpID { 138 if impression.Banner != nil { 139 return openrtb_ext.BidTypeBanner, nil 140 } 141 if impression.Video != nil { 142 return openrtb_ext.BidTypeVideo, nil 143 } 144 if impression.Native != nil { 145 return openrtb_ext.BidTypeNative, nil 146 } 147 } 148 } 149 150 return "", &errortypes.BadServerResponse{ 151 Message: fmt.Sprintf("The impression with ID %s is not present into the request", bid.ImpID), 152 } 153 }