github.com/prebid/prebid-server@v0.275.0/endpoints/info/bidders_detail.go (about)

     1  package info
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/golang/glog"
    10  	"github.com/julienschmidt/httprouter"
    11  	"github.com/prebid/prebid-server/config"
    12  	"github.com/prebid/prebid-server/openrtb_ext"
    13  )
    14  
    15  const (
    16  	statusActive   string = "ACTIVE"
    17  	statusDisabled string = "DISABLED"
    18  )
    19  
    20  // NewBiddersDetailEndpoint builds a handler for the /info/bidders/<bidder> endpoint.
    21  func NewBiddersDetailEndpoint(bidders config.BidderInfos, aliases map[string]string) httprouter.Handle {
    22  	responses, err := prepareBiddersDetailResponse(bidders, aliases)
    23  	if err != nil {
    24  		glog.Fatalf("error creating /info/bidders/<bidder> endpoint response: %v", err)
    25  	}
    26  
    27  	return func(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) {
    28  		bidder := ps.ByName("bidderName")
    29  
    30  		if response, ok := responses[bidder]; ok {
    31  			w.Header().Set("Content-Type", "application/json")
    32  			if _, err := w.Write(response); err != nil {
    33  				glog.Errorf("error writing response to /info/bidders/%s: %v", bidder, err)
    34  			}
    35  		} else {
    36  			w.WriteHeader(http.StatusNotFound)
    37  		}
    38  	}
    39  }
    40  
    41  func prepareBiddersDetailResponse(bidders config.BidderInfos, aliases map[string]string) (map[string][]byte, error) {
    42  	details, err := mapDetails(bidders, aliases)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	responses, err := marshalDetailsResponse(details)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	all, err := marshalAllResponse(responses)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	responses["all"] = all
    57  
    58  	return responses, nil
    59  }
    60  
    61  func mapDetails(bidders config.BidderInfos, aliases map[string]string) (map[string]bidderDetail, error) {
    62  	details := map[string]bidderDetail{}
    63  
    64  	for bidderName, bidderInfo := range bidders {
    65  		details[bidderName] = mapDetailFromConfig(bidderInfo)
    66  	}
    67  
    68  	for aliasName, bidderName := range aliases {
    69  		aliasBaseInfo, aliasBaseInfoFound := details[bidderName]
    70  		if !aliasBaseInfoFound {
    71  			return nil, fmt.Errorf("base adapter %s for alias %s not found", bidderName, aliasName)
    72  		}
    73  
    74  		aliasInfo := aliasBaseInfo
    75  		aliasInfo.AliasOf = bidderName
    76  		details[aliasName] = aliasInfo
    77  	}
    78  
    79  	return details, nil
    80  }
    81  
    82  func marshalDetailsResponse(details map[string]bidderDetail) (map[string][]byte, error) {
    83  	responses := map[string][]byte{}
    84  
    85  	for bidder, detail := range details {
    86  		json, err := json.Marshal(detail)
    87  		if err != nil {
    88  			return nil, fmt.Errorf("unable to marshal info for bidder %s: %v", bidder, err)
    89  		}
    90  		responses[bidder] = json
    91  	}
    92  
    93  	return responses, nil
    94  }
    95  
    96  func marshalAllResponse(responses map[string][]byte) ([]byte, error) {
    97  	responsesJSON := make(map[string]json.RawMessage, len(responses))
    98  
    99  	for k, v := range responses {
   100  		responsesJSON[k] = json.RawMessage(v)
   101  	}
   102  
   103  	json, err := json.Marshal(responsesJSON)
   104  	if err != nil {
   105  		return nil, fmt.Errorf("unable to marshal info for bidder all: %v", err)
   106  	}
   107  	return json, nil
   108  }
   109  
   110  type bidderDetail struct {
   111  	Status       string        `json:"status"`
   112  	UsesHTTPS    *bool         `json:"usesHttps,omitempty"`
   113  	Maintainer   *maintainer   `json:"maintainer,omitempty"`
   114  	Capabilities *capabilities `json:"capabilities,omitempty"`
   115  	AliasOf      string        `json:"aliasOf,omitempty"`
   116  }
   117  
   118  type maintainer struct {
   119  	Email string `json:"email"`
   120  }
   121  
   122  type capabilities struct {
   123  	App  *platform `json:"app,omitempty"`
   124  	Site *platform `json:"site,omitempty"`
   125  }
   126  
   127  type platform struct {
   128  	MediaTypes []string `json:"mediaTypes"`
   129  }
   130  
   131  func mapDetailFromConfig(c config.BidderInfo) bidderDetail {
   132  	var bidderDetail bidderDetail
   133  
   134  	if c.Maintainer != nil {
   135  		bidderDetail.Maintainer = &maintainer{
   136  			Email: c.Maintainer.Email,
   137  		}
   138  	}
   139  
   140  	if c.IsEnabled() {
   141  		bidderDetail.Status = statusActive
   142  
   143  		usesHTTPS := strings.HasPrefix(strings.ToLower(c.Endpoint), "https://")
   144  		bidderDetail.UsesHTTPS = &usesHTTPS
   145  
   146  		if c.Capabilities != nil {
   147  			bidderDetail.Capabilities = &capabilities{}
   148  
   149  			if c.Capabilities.App != nil {
   150  				bidderDetail.Capabilities.App = &platform{
   151  					MediaTypes: mapMediaTypes(c.Capabilities.App.MediaTypes),
   152  				}
   153  			}
   154  
   155  			if c.Capabilities.Site != nil {
   156  				bidderDetail.Capabilities.Site = &platform{
   157  					MediaTypes: mapMediaTypes(c.Capabilities.Site.MediaTypes),
   158  				}
   159  			}
   160  		}
   161  	} else {
   162  		bidderDetail.Status = statusDisabled
   163  	}
   164  
   165  	return bidderDetail
   166  }
   167  
   168  func mapMediaTypes(m []openrtb_ext.BidType) []string {
   169  	mediaTypes := make([]string, len(m))
   170  
   171  	for i, v := range m {
   172  		mediaTypes[i] = string(v)
   173  	}
   174  
   175  	return mediaTypes
   176  }