Skip to content

Commit

Permalink
Added adapter param schemas & endpoint (prebid#147)
Browse files Browse the repository at this point in the history
* Added schema files for a few users, and an endpoint which serves them.

* Added some comments.

* Added tests, and named the function more generally.

* Removed t.Helper(), which doesnt exist in Go 1.8

* Made the facebook placementId required.

* Added schemas for all the other bidders.

* Modified the tests so that they force all adapters to have uploaded a schema.

* Added documentation.

* Added the two new params to the rubicon schema.

* Moved .md file so that the file path parallels the URL
  • Loading branch information
dbemiller authored Oct 17, 2017
1 parent 9c2efea commit 8875819
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 0 deletions.
24 changes: 24 additions & 0 deletions docs/endpoints/bidders/params.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## GET /bidders/params

This endpoint gets informatoin about all the custom bidders params that Prebid Server supports.

### Returns

A JSON object whose keys are bidder codes, and values are Draft 4 JSON schemas which describe that bidders' params.

For example:

```
{
"appnexus": { /* A json-schema describing AppNexus' bidder params */ },
"rubicon": { /* A json-schema describing Rubicon's bidder params */ }
... all other bidders will have similar keys & values here ...
}
```

The exact contents of the json-schema values can be found [here](../../../static/bidder-params).

### See also

- [JSON schema homepage](http://json-schema.org/specification-links.html#draft-4)
- [Understanding JSON schema](https://spacetelescope.github.io/understanding-json-schema/)
39 changes: 39 additions & 0 deletions pbs_light.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type bidResult struct {
bid_list pbs.PBSBidSlice
}

const schemaDirectory = "./static/bidder-params"

const defaultPriceGranularity = "med"

// Constant keys for ad server targeting for responses to Prebid Mobile
Expand Down Expand Up @@ -438,6 +440,42 @@ func status(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
// could add more logic here, but doing nothing means 200 OK
}

// NewJsonDirectoryServer is used to serve .json files from a directory as a single blob. For example,
// given a directory containing the files "a.json" and "b.json", this returns a Handle which serves JSON like:
//
// {
// "a": { ... content from the file a.json ... },
// "b": { ... content from the file b.json ... }
// }
//
// This function stores the file contents in memory, and should not be used on large directories.
// If the root directory, or any of the files in it, cannot be read, then the program will exit.
func NewJsonDirectoryServer(schemaDirectory string) httprouter.Handle {
// Slurp the files into memory first, since they're small and it minimizes request latency.
files, err := ioutil.ReadDir(schemaDirectory)
if err != nil {
glog.Fatalf("Failed to read directory %s: %v", schemaDirectory, err)
}

data := make(map[string]json.RawMessage, len(files))
for _, file := range files {
bytes, err := ioutil.ReadFile(fmt.Sprintf("%s/%s", schemaDirectory, file.Name()))
if err != nil {
glog.Fatalf("Failed to read file %s/%s: %v", schemaDirectory, file.Name(), err)
}
data[file.Name()[0:len(file.Name())-5]] = json.RawMessage(bytes)
}
response, err := json.Marshal(data)
if err != nil {
glog.Fatalf("Failed to marshal bidder param JSON-schema: %v", err)
}

return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Header().Add("Content-Type", "application/json")
w.Write(response)
}
}

func serveIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
http.ServeFile(w, r, "static/index.html")
}
Expand Down Expand Up @@ -645,6 +683,7 @@ func serve(cfg *config.Configuration) error {

router := httprouter.New()
router.POST("/auction", (&auctionDeps{m}).auction)
router.GET("/bidders/params", NewJsonDirectoryServer(schemaDirectory))
router.POST("/cookie_sync", (&cookieSyncDeps{m}).cookieSync)
router.POST("/validate", validate)
router.GET("/status", status)
Expand Down
46 changes: 46 additions & 0 deletions pbs_light_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ import (
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/pbs"
"github.com/prebid/prebid-server/pbsmetrics"
"io/ioutil"
"strings"
)

const adapterDirectory = "adapters"

func TestCookieSyncNoCookies(t *testing.T) {
cfg, err := config.New()
if err != nil {
Expand Down Expand Up @@ -415,3 +419,45 @@ func TestBidSizeValidate(t *testing.T) {
}
}
}

func TestNewJsonDirectoryServer(t *testing.T) {

handler := NewJsonDirectoryServer(schemaDirectory)
recorder := httptest.NewRecorder()
request, _ := http.NewRequest("GET", "/whatever", nil)
handler(recorder, request, nil)

var data map[string]json.RawMessage
json.Unmarshal(recorder.Body.Bytes(), &data)

// Make sure that every adapter has a json schema file associated with it
adapterFiles, err := ioutil.ReadDir(adapterDirectory)
if err != nil {
t.Fatalf("Failed to open the adapters directory: %v", err)
}

var nonAdapterFiles = []string{"adapter.go", "openrtb_util.go"}

for _, adapterFile := range adapterFiles {
if contains(nonAdapterFiles, adapterFile.Name()) || strings.HasSuffix(adapterFile.Name(), "_test.go") {
continue
}
adapterName := adapterFile.Name()[0 : len(adapterFile.Name())-3] // transform "index.go" into "index"
ensureHasKey(t, data, adapterName)
}
}

func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

func ensureHasKey(t *testing.T, data map[string]json.RawMessage, key string) {
if _, ok := data[key]; !ok {
t.Errorf("Expected map to produce a schema for adapter: %s", key)
}
}
65 changes: 65 additions & 0 deletions static/bidder-params/appnexus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Appnexus Adapter Params",
"description": "A schema which validates params accepted by the AppNexus adapter",

"type": "object",
"properties": {
"placementId": {
"type": "integer",
"description": "An ID which identifies this placement of the impression"
},
"invCode": {
"type": "string",
"description": "A code identifying the inventory of this placement."
},
"member": {
"type": "string",
"description": "An ID which identifies the member selling the impression."
},
"keywords": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"description": "A key with one or more values associated with it. These are used in buy-side segment targeting.",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
}
},
"required": ["key", "value"]
}
},
"trafficSourceCode": {
"type": "string",
"description": "Specifies the third-party source of this impression."
},
"reserve": {
"type": "number",
"description": "The minimium acceptable bid, in CPM, using US Dollars"
},
"position": {
"type": "string",
"enum": ["above", "below"],
"description": "Specifies the ad unit as above or below the fold"
}
},

"oneOf": [{
"required": ["placementId"]
}, {
"required": ["invCode", "member"]
}],

"not": {
"required": ["placementId", "invCode", "member"]
}
}
13 changes: 13 additions & 0 deletions static/bidder-params/facebook.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Facebook Adapter Params",
"description": "A schema which validates params accepted by the Facebook adapter",
"type": "object",
"properties": {
"placementId": {
"type": "string",
"description": "An ID which identifies the placement selling the impression"
}
},
"required": ["placementId"]
}
13 changes: 13 additions & 0 deletions static/bidder-params/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Index Adapter Params",
"description": "A schema which validates params accepted by the Index adapter",
"type": "object",
"properties": {
"siteID": {
"type": "integer",
"description": "An ID which identifies the site selling the impression"
}
},
"required": ["siteID"]
}
13 changes: 13 additions & 0 deletions static/bidder-params/lifestreet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Lifestreet Adapter Params",
"description": "A schema which validates params accepted by the Lifestreet adapter",
"type": "object",
"properties": {
"slot_tag": {
"type": "string",
"description": "A tag which identifies the ad slot"
}
},
"required": ["slot_tag"]
}
17 changes: 17 additions & 0 deletions static/bidder-params/pubmatic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Pubmatic Adapter Params",
"description": "A schema which validates params accepted by the Pubmatic adapter",
"type": "object",
"properties": {
"publisherId": {
"type": "string",
"description": "An ID which identifies the publisher"
},
"adSlot": {
"type": "string",
"description": "An ID which identifies the ad slot"
}
},
"required": ["publisherId", "adSlot"]
}
22 changes: 22 additions & 0 deletions static/bidder-params/pulsepoint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Pulsepoint Adapter Params",
"description": "A schema which validates params accepted by the Pulsepoint adapter",
"type": "object",
"properties": {
"cp": {
"type": "integer",
"description": "An ID which identifies the publisher selling the impression"
},
"ct": {
"type": "integer",
"description": "An ID which identifies the ad slot being sold"
},
"cf": {
"type": "string",
"pattern": "^[0-9]+x[0-9]+$",
"description": "The size of the ad slot being sold. This should be a string like 300x250"
}
},
"required": ["cp", "ct", "cf"]
}
35 changes: 35 additions & 0 deletions static/bidder-params/rubicon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Rubicon Adapter Params",
"description": "A schema which validates params accepted by the Rubicon adapter",
"type": "object",
"properties": {
"accountId": {
"type": "integer",
"description": "An ID which identifies the publisher's account"
},
"siteId": {
"type": "integer",
"description": "An ID which identifies the site selling the impression"
},
"zoneId": {
"type": "integer",
"description": "An ID which identifies the sub-section of the site where the impression is located"
},
"inventory": {
"type": "object",
"description": "An object defining arbitrary targeting key/value pairs related to the page",
"additionalProperties": {
"type": "string"
}
},
"visitor": {
"type": "object",
"description": "An object defining arbitrary targeting key/value pairs related to the visitor",
"additionalProperties": {
"type": "string"
}
}
},
"required": ["accountId", "siteId", "zoneId"]
}

0 comments on commit 8875819

Please sign in to comment.