Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cbb934a

Browse files
authored
Document for adding a PBS Go Module (prebid#4225)
1 parent a26d7a5 commit cbb934a

File tree

4 files changed

+674
-37
lines changed

4 files changed

+674
-37
lines changed
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
---
2+
layout: page_v2
3+
sidebarType: 5
4+
title: Prebid Server | Developers | Adding a Go Module
5+
6+
---
7+
8+
# Prebid Server - Adding a Go Module
9+
{: .no_toc}
10+
11+
* TOC
12+
{:toc }
13+
14+
## Overview
15+
16+
This document details how to make a module for PBS-Go.
17+
18+
You will want to be familiar with the following background information:
19+
20+
- the [module overview](/prebid-server/developers/add-a-module.html)
21+
- the [PBS-Go Modularity Tech Spec](https://docs.google.com/document/d/1CmamniQpwcI3p0_rHe2F17zV4sEhzpOdrqU7zuZVZ_I/edit?usp=sharing)
22+
23+
### Contributing
24+
25+
Check out the [PBS-Go contribution guide](https://github.com/prebid/prebid-server/blob/master/docs/developers/contributing.md) before introducing any code changes.
26+
27+
## Module Directory Layout
28+
29+
The Prebid Server repository contains a package `modules` located in the root project directory. It includes all available PBS modules. So, in order to add a new module, fork the repository and create a folder with the desired name inside the `modules` folder with the following structure:
30+
31+
```
32+
+- prebid-server/
33+
+- modules/ <- package with modules that implement various hooks
34+
+- builder.go <- contains a list of all available modules
35+
+- {YOUR_VENDOR_NAME}/ <- top-level package used to group modules from the same vendor
36+
+- {YOUR_MODULE_NAME}/ <- package with source code of your module
37+
+- module.go <- file with module initialization function
38+
```
39+
Module directory names (`{YOUR_VENDOR_NAME}/YOUR_MODULE_NAME/}`) must consist of valid identifiers.
40+
A valid identifier is defined as a sequence of one or more letters, including an underscore character (`_`), and digits.
41+
All other symbols such as `-`, `.`, etc. are not permitted.
42+
43+
### Your module's build file
44+
45+
Here's a partial example of your module-specific `module.go` file:
46+
47+
```
48+
package your_module_name
49+
50+
import (
51+
"context"
52+
"encoding/json"
53+
54+
"github.com/prebid/prebid-server/hooks/hookstage"
55+
"github.com/prebid/prebid-server/modules/moduledeps"
56+
)
57+
58+
func Builder(config json.RawMessage, deps moduledeps.ModuleDeps) (interface{}, error) {
59+
return Module{}, nil
60+
}
61+
62+
// Module must implement at least 1 hook interface.
63+
type Module struct{}
64+
65+
func (m Module) HandleBidderRequestHook(
66+
ctx context.Context,
67+
invocationCtx hookstage.ModuleInvocationContext,
68+
payload hookstage.BidderRequestPayload,
69+
) (hookstage.HookResult[hookstage.BidderRequestPayload], error) {
70+
result := hookstage.HookResult[hookstage.BidderRequestPayload]{}
71+
72+
// hook handling logic
73+
74+
return result, nil
75+
}
76+
```
77+
78+
In the example above, our module only implements the `bidder-request` hook interface.
79+
80+
The module's `Builder` function receives 2 arguments:
81+
1. `config json.RawMessage` - represents a global config of your module, see [Configuration](#configuration).
82+
2. `deps moduledeps.ModuleDeps` - contains dependencies that your module might require.
83+
84+
and returns 2 values:
85+
1. `interface{}` - must implement at least 1 hook interface, see [hooks](#hook-interfaces). PBS uses type assertion to find out which hook interfaces implemented by module.
86+
2. `error` - any error occurred during module initialization.
87+
88+
### Expose your module to PBS
89+
90+
All available modules are exposed through the `modules/builder.go` file. This file is auto-generated, so you shouldn’t edit it manually.
91+
92+
To register a new module, you just need to run one of the following commands from the PBS root directory:
93+
- `make build-modules`
94+
- or `go generate modules/modules.go`
95+
96+
This command scans the `modules/` directory for files matching the pattern `modules/*/*/module.go` and adds all matching packages to the `modules/builder.go` file.
97+
98+
## Module Code
99+
100+
The quick start is to take a look in two places:
101+
- the [prebid ortb2blocking module](https://github.com/prebid/prebid-server/tree/master/modules/prebid/ortb2blocking)
102+
- the [hook source code and tests](https://github.com/prebid/prebid-server/tree/master/hooks)
103+
104+
### Adding module documentation
105+
It is required to add a "README.md" file to the root of your module folder. It's recommended to specify the description of what the implemented module does, links to external documentation and include maintainer contact info (email, slack, etc).
106+
107+
The documentation must also live on the docs.prebid.org site. Please add a markdown file to https://github.com/prebid/prebid.github.io/tree/master/prebid-server/pbs-modules
108+
109+
### Hook Interfaces
110+
111+
The Prebid server processing workflow is divided into several 'stages' where module authors can inject a specific function signature called a 'hook'.
112+
113+
The Prebid Server host company will define which modules to run in which order by setting up a configuration defining which hooks run serially and which can run in parallel.
114+
115+
The supported stages are described in the [general module overview](/prebid-server/developers/add-a-module.html#2-understand-the-endpoints-and-stages) and in PBS-Core source code at the "github.com/prebid/prebid-server/hooks" package.
116+
117+
These are the available hooks that can be implemented in a module:
118+
119+
- github.com/prebid/prebid-server/hooks/hookstage.Entrypoint
120+
- github.com/prebid/prebid-server/hooks/hookstage.RawAuctionRequest
121+
- github.com/prebid/prebid-server/hooks/hookstage.ProcessedAuctionRequest
122+
- github.com/prebid/prebid-server/hooks/hookstage.BidderRequest
123+
- github.com/prebid/prebid-server/hooks/hookstage.RawBidderResponse
124+
- github.com/prebid/prebid-server/hooks/hookstage.AllProcessedBidResponses
125+
- github.com/prebid/prebid-server/hooks/hookstage.AuctionResponse
126+
127+
In a module it is not necessary to implement all mentioned interfaces but at least one is required by your functionality.
128+
129+
### Examples
130+
131+
1) To **update** the request in the `BidderRequest`, your implementation would return a hook result with a change set:
132+
```
133+
import (
134+
"context"
135+
136+
"github.com/prebid/prebid-server/hooks/hookstage"
137+
)
138+
139+
type Module struct{}
140+
141+
func (m Module) HandleBidderRequestHook(
142+
ctx context.Context,
143+
invocationCtx hookstage.ModuleInvocationContext,
144+
payload hookstage.BidderRequestPayload,
145+
) (hookstage.HookResult[hookstage.BidderRequestPayload], error) {
146+
changeSet := hookstage.ChangeSet[hookstage.BidderRequestPayload]{}
147+
changeSet.BidderRequest().BAdv().Update([]string{"a.com"})
148+
149+
return hookstage.HookResult[hookstage.BidderRequestPayload]{ChangeSet: changeSet}, nil
150+
}
151+
```
152+
153+
Please note, the `hookstage.ChangeSet` has a restricted set of methods, but methods can be easily extended when more use cases come up.
154+
155+
For more complex payload updates, you can choose another method:
156+
```
157+
func (m Module) HandleBidderRequestHook(
158+
ctx context.Context,
159+
invocationCtx hookstage.ModuleInvocationContext,
160+
payload hookstage.BidderRequestPayload,
161+
) (hookstage.HookResult[hookstage.BidderRequestPayload], error) {
162+
battrByImp := map[string][]adcom1.CreativeAttribute{"imp_ID1": []adcom1.CreativeAttribute{adcom1.AttrAudioAuto}}
163+
changeSet := hookstage.ChangeSet[hookstage.BidderRequestPayload]{}
164+
changeSet.AddMutation(func(payload hookstage.BidderRequestPayload) (hookstage.BidderRequestPayload, error) {
165+
for i, imp := range payload.BidRequest.Imp {
166+
if battr, ok := battrByImp[imp.ID]; ok {
167+
imp.Banner.BAttr = battr
168+
payload.BidRequest.Imp[i] = imp
169+
}
170+
}
171+
return payload, nil
172+
}, hookstage.MutationUpdate, "bidrequest", "imp", "banner", "battr")
173+
174+
return hookstage.HookResult[hookstage.BidderRequestPayload]{ChangeSet: changeSet}, nil
175+
}
176+
```
177+
178+
2) To **reject** the bidder in the `BidderRequest`, your hook implementation would return a hook result with a reject flag and an NBR code:
179+
```
180+
func (m Module) HandleBidderRequestHook(
181+
ctx context.Context,
182+
invocationCtx hookstage.ModuleInvocationContext,
183+
payload hookstage.BidderRequestPayload,
184+
) (hookstage.HookResult[hookstage.BidderRequestPayload], error) {
185+
return hookstage.HookResult[hookstage.BidderRequestPayload]{Reject: true, NbrCode: 7}, nil
186+
}
187+
```
188+
189+
Refer [here](https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/OpenRTB%20v3.0%20FINAL.md#list--no-bid-reason-codes-) for a list of available No Bid Response Codes.
190+
191+
3) To supply [analytics tags](/prebid-server/developers/module-atags.html) in the `BidderRequest`, your hook implementation would return a hook result with analytics tags:
192+
```
193+
import (
194+
"context"
195+
196+
"github.com/prebid/prebid-server/hooks/hookstage"
197+
"github.com/prebid/prebid-server/hooks/hookanalytics"
198+
)
199+
200+
func (m Module) HandleBidderRequestHook(
201+
ctx context.Context,
202+
invocationCtx hookstage.ModuleInvocationContext,
203+
payload hookstage.BidderRequestPayload,
204+
) (hookstage.HookResult[hookstage.BidderRequestPayload], error) {
205+
return hookstage.HookResult[hookstage.BidderRequestPayload]{
206+
AnalyticsTags: hookanalytics.Analytics{
207+
Activities: []hookanalytics.Activity{
208+
{
209+
Name: "enforce_blocking",
210+
Status: hookanalytics.ActivityStatusSuccess,
211+
Results: []hookanalytics.Result{
212+
{
213+
Status: hookanalytics.ResultStatusBlock,
214+
Values: map[string]interface{}{
215+
"attributes": []string{"bcat"},
216+
"bcat": []string{"IAB-1"},
217+
},
218+
AppliedTo: hookanalytics.AppliedTo{Bidder: "appnexus", ImpIds: []string{"imp_ID1"}},
219+
},
220+
{
221+
Status: hookanalytics.ResultStatusAllow,
222+
AppliedTo: hookanalytics.AppliedTo{Bidder: "appnexus", ImpIds: []string{"imp_ID2"}},
223+
},
224+
},
225+
},
226+
},
227+
},
228+
}, nil
229+
}
230+
```
231+
232+
More test implementations for each hook can be found in unit-tests at [https://github.com/prebid/prebid-server/tree/master/modules/prebid/ortb2blocking](https://github.com/prebid/prebid-server/tree/master/modules/prebid/ortb2blocking) folder.
233+
234+
### Configuration
235+
236+
It's possible to define default module configuration which can be read by the module at PBS startup. Please see the [Configuration](https://docs.google.com/document/d/1CmamniQpwcI3p0_rHe2F17zV4sEhzpOdrqU7zuZVZ_I/edit#heading=h.mh3urph3k1mk) section of the technical specification.
237+
238+
An example configuration for hooks might look like this:
239+
```json
240+
{
241+
"hooks": {
242+
"enabled": true,
243+
"modules": {
244+
"vendor1": {
245+
"module1": {
246+
"enabled": true
247+
}
248+
}
249+
},
250+
"host_execution_plan": {
251+
"endpoints": {
252+
"/openrtb2/auction": {
253+
"stages": {
254+
"bidder_request": {
255+
"groups": [
256+
{
257+
"timeout": 10,
258+
"hook_sequence": [
259+
{
260+
"module_code": "vendor1.module1",
261+
"hook_impl_code": "code123"
262+
}
263+
]
264+
}
265+
]
266+
}
267+
}
268+
}
269+
}
270+
}
271+
}
272+
}
273+
```
274+
275+
### Testing
276+
277+
Unit tests are required. Each implemented hook must be at least 90% covered by unit tests.
278+
279+
### How to build and install a module
280+
281+
Read about the module building in the [building section](https://docs.google.com/document/d/1CmamniQpwcI3p0_rHe2F17zV4sEhzpOdrqU7zuZVZ_I/edit#heading=h.o8dv0neoq4xm) of the technical specification.
282+
283+
## Analytics Adapters and Modules
284+
285+
Each module can inject analytics tags into the request as described in the analytics tags section.
286+
287+
Analytics adapters receive these tags through the Auction/AMP analytic object.
288+
289+
To get analytics tags you need to go into:
290+
291+
```
292+
AuctionObject/AmpObject
293+
-> HookExecutionOutcome (iterate through stages)
294+
-> Groups (iterate through groups)
295+
-> InvocationResults (go through hooks invocation results and find interested one)
296+
-> AnalyticsTags
297+
```
298+
299+
The `AnalyticsTags` object has activities with collection of `github.com/prebid/prebid-server/hooks/hookanalytics.Result` objects inside. Each `Result` has the `Values` field which holds arbitrary values set by a module.
300+
301+
It depends on the particular module implementation how to parse their analytics tags, since the internal structure is custom and depends on the module. Therefore, analytics modules that want to report on specific behavior need to be coded to know about that module. See the prebid ortb2blocking module for an example of what analytics tags may be available.
302+
303+
## Further Reading
304+
305+
- [PBS Module Overview](/prebid-server/developers/add-a-module.html)
306+
- [PBS Module Analytics Tags Conventions](/prebid-server/developers/module-atags.html)

prebid-server/developers/add-a-module-java.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ The documentation must also live on the docs.prebid.org site. Please add a markd
105105

106106
### Hook Interfaces
107107

108-
The Prebid server processing workflow is divided into serveal 'stages' where module authors can code agaist a specific function signature called a 'hook'.
108+
The Prebid server processing workflow is divided into several 'stages' where module authors can code agaist a specific function signature called a 'hook'.
109109

110110
The Prebid Server host company will define which modules to run in which order by setting up a configuration defining which hooks run, and which can run in parallel.
111111

prebid-server/developers/add-a-module.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ title: Prebid Server | Developers | Adding a Module
1111
This document guides you through the process of developing a module for host companies to plug into their instance of Prebid Server.
1212
We encourage you to look at existing modules for working examples. You can also ask us questions by [submitting a GitHub issue](https://github.com/prebid/prebid-server/issues/new).
1313

14-
{: .alert.alert-info :}
15-
Modules are currently only supported in [PBS-Java](https://github.com/prebid/prebid-server-java).
16-
17-
1814
* TOC
1915
{:toc }
2016

@@ -23,7 +19,7 @@ Modules are currently only supported in [PBS-Java](https://github.com/prebid/pre
2319
The ability to add optional modules in [Prebid.js](/prebid/prebidjs.html) has been widely used,
2420
with dozens of interesting features forming a healthy ecosystem of vendor choice that's good for publishers and the industry.
2521

26-
Prebid Server (Java) supports a rich module interface that
22+
Prebid Server supports a rich module interface that
2723
allows anyone to contribute functionality at predefined places
2824
along the request pipeline. Here's the general development process:
2925

@@ -162,7 +158,7 @@ about how to format ATags.
162158
The details of the implementation depend on the platform.
163159

164160
- PBS-Java: see [Adding a PBS-Java module](/prebid-server/developers/add-a-module-java.html)
165-
- PBS-Go: TBD
161+
- PBS-Go: see [Adding a PBS-Go module](/prebid-server/developers/add-a-module-go.html)
166162

167163
Other rules for open source PBS pull request:
168164

0 commit comments

Comments
 (0)