Skip to content

Commit 97b8056

Browse files
namespace routes helpers
1 parent 1546809 commit 97b8056

File tree

4 files changed

+77
-14
lines changed

4 files changed

+77
-14
lines changed

crates/common/src/integrations/prebid.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use crate::settings::{IntegrationConfig, Settings};
2626
use crate::synthetic::{generate_synthetic_id, get_or_generate_synthetic_id};
2727

2828
const PREBID_INTEGRATION_ID: &str = "prebid";
29+
30+
// Legacy route paths (kept for backwards compatibility)
2931
const ROUTE_FIRST_PARTY_AD: &str = "/first-party/ad";
3032
const ROUTE_THIRD_PARTY_AD: &str = "/third-party/ad";
3133

@@ -136,7 +138,11 @@ impl PrebidIntegration {
136138
},
137139
)?;
138140

139-
log::info!("/third-party/ad: received {} adUnits", body.ad_units.len());
141+
log::info!(
142+
"{}: received {} adUnits",
143+
ROUTE_THIRD_PARTY_AD,
144+
body.ad_units.len()
145+
);
140146
for unit in &body.ad_units {
141147
if let Some(mt) = &unit.media_types {
142148
if let Some(banner) = &mt.banner {
@@ -264,6 +270,10 @@ pub fn register(settings: &Settings) -> Option<IntegrationRegistration> {
264270

265271
#[async_trait(?Send)]
266272
impl IntegrationProxy for PrebidIntegration {
273+
fn integration_name(&self) -> &'static str {
274+
PREBID_INTEGRATION_ID
275+
}
276+
267277
fn routes(&self) -> Vec<IntegrationEndpoint> {
268278
let mut routes = vec![
269279
IntegrationEndpoint::get(ROUTE_FIRST_PARTY_AD),

crates/common/src/integrations/registry.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,13 @@ impl IntegrationEndpoint {
121121
/// Trait implemented by integration proxies that expose HTTP endpoints.
122122
#[async_trait(?Send)]
123123
pub trait IntegrationProxy: Send + Sync {
124-
/// Routes handled by this integration (e.g. `/integrations/example/auction`).
124+
/// Integration identifier used for logging and optional URL namespace.
125+
/// Use this with the `namespaced_*` helper methods to automatically prefix routes.
126+
fn integration_name(&self) -> &'static str;
127+
128+
/// Routes handled by this integration.
129+
/// to automatically namespace routes under `/integrations/{integration_name()}/`,
130+
/// or define routes manually for backwards compatibility.
125131
fn routes(&self) -> Vec<IntegrationEndpoint>;
126132

127133
/// Handle the proxied request.
@@ -130,6 +136,30 @@ pub trait IntegrationProxy: Send + Sync {
130136
settings: &Settings,
131137
req: Request,
132138
) -> Result<Response, Report<TrustedServerError>>;
139+
140+
/// Helper to create a namespaced GET endpoint.
141+
/// Automatically prefixes the path with `/integrations/{integration_name()}`.
142+
///
143+
/// # Example
144+
/// ```ignore
145+
/// self.namespaced_get("/auction") // becomes /integrations/my_integration/auction
146+
/// ```
147+
fn get(&self, path: &str) -> IntegrationEndpoint {
148+
let full_path = format!("/integrations/{}{}", self.integration_name(), path);
149+
IntegrationEndpoint::get(Box::leak(full_path.into_boxed_str()))
150+
}
151+
152+
/// Helper to create a namespaced POST endpoint.
153+
/// Automatically prefixes the path with `/integrations/{integration_name()}`.
154+
///
155+
/// # Example
156+
/// ```ignore
157+
/// self.namespaced_post("/auction") // becomes /integrations/my_integration/auction
158+
/// ```
159+
fn post(&self, path: &str) -> IntegrationEndpoint {
160+
let full_path = format!("/integrations/{}{}", self.integration_name(), path);
161+
IntegrationEndpoint::post(Box::leak(full_path.into_boxed_str()))
162+
}
133163
}
134164

135165
/// Trait for integration-provided HTML attribute rewrite hooks.
@@ -443,6 +473,10 @@ mod tests {
443473

444474
#[async_trait(?Send)]
445475
impl IntegrationProxy for MockProxy {
476+
fn integration_name(&self) -> &'static str {
477+
"test"
478+
}
479+
446480
fn routes(&self) -> Vec<IntegrationEndpoint> {
447481
vec![]
448482
}

crates/common/src/integrations/testlight.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,12 @@ pub fn register(settings: &Settings) -> Option<IntegrationRegistration> {
121121

122122
#[async_trait(?Send)]
123123
impl IntegrationProxy for TestlightIntegration {
124+
fn integration_name(&self) -> &'static str {
125+
TESTLIGHT_INTEGRATION_ID
126+
}
127+
124128
fn routes(&self) -> Vec<IntegrationEndpoint> {
125-
vec![IntegrationEndpoint::post("/integrations/testlight/auction")]
129+
vec![self.post("/auction")]
126130
}
127131

128132
async fn handle(

docs/integration_guide.md

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,14 @@ Implement the trait from `registry.rs` when your integration needs its own HTTP
112112
```rust
113113
#[async_trait(?Send)]
114114
impl IntegrationProxy for MyIntegration {
115+
fn integration_name(&self) -> &'static str {
116+
"my_integration"
117+
}
118+
115119
fn routes(&self) -> Vec<IntegrationEndpoint> {
116120
vec![
117-
IntegrationEndpoint::post("/integrations/my-integration/auction"),
118-
IntegrationEndpoint::get("/integrations/my-integration/status"),
121+
self.post("/auction"),
122+
self.get("/status"),
119123
]
120124
}
121125

@@ -129,11 +133,20 @@ impl IntegrationProxy for MyIntegration {
129133
}
130134
```
131135

132-
Routes are matched verbatim in `crates/fastly/src/main.rs`, so stick to stable paths
133-
(`/integrations/<id>/…`) and register whichever HTTP methods you need. The shared context
134-
already injects Trusted Server logging, headers, and error handling; the handler only
135-
needs to deserialize the request, call the upstream endpoint, and stamp integration-specific
136-
headers.
136+
**Recommended:** Use the provided helper methods `get()` or `post()`
137+
to automatically namespace your routes under `/integrations/{integration_name()}/`.
138+
This lets you define routes with just their relative paths (e.g., `self.post("/auction")` becomes
139+
`"/integrations/my_integration/auction"`). You can also define routes manually using
140+
`IntegrationEndpoint::get()` / `IntegrationEndpoint::post()` for backwards compatibility or
141+
special cases.
142+
143+
Routes are matched verbatim in `crates/fastly/src/main.rs`, so stick to stable paths and
144+
register whichever HTTP methods you need. **New integrations should namespace their routes under
145+
`/integrations/{INTEGRATION_NAME}/`** using the helper methods (`self.get()` or `self.post()`)
146+
for consistency, but you can define routes manually if needed (e.g., for backwards compatibility).
147+
The shared context already injects Trusted Server logging, headers,
148+
and error handling; the handler only needs to deserialize the request, call the upstream endpoint,
149+
and stamp integration-specific headers.
137150

138151
#### Proxying upstream requests
139152

@@ -308,10 +321,12 @@ Prebid applies the same steps outlined above with a few notable patterns:
308321
`settings.integrations.insert_config("prebid", &serde_json::json!({...}))`, the same helper that
309322
other integrations use.
310323

311-
2. **Routes owned by the integration**`IntegrationProxy::routes` declares the legacy
312-
`/first-party/ad` (GET) and `/third-party/ad` (POST) endpoints. Both handlers share helpers that
313-
shape OpenRTB payloads, inject synthetic IDs + geo/request-signing context, forward requests via
314-
`ensure_backend_from_url`, and run the HTML creative rewrites before responding.
324+
2. **Routes owned by the integration**`IntegrationProxy::routes` declares the
325+
`/integrations/prebid/first-party/ad` (GET) and `/integrations/prebid/third-party/ad` (POST)
326+
endpoints. Both handlers share helpers that shape OpenRTB payloads, inject synthetic IDs +
327+
geo/request-signing context, forward requests via `ensure_backend_from_url`, and run the HTML
328+
creative rewrites before responding. All routes are properly namespaced under
329+
`/integrations/prebid/` to follow the integration routing pattern.
315330

316331
3. **HTML rewrites through the registry** – When `auto_configure` is enabled, the integration’s
317332
`IntegrationAttributeRewriter` removes any `<script src="prebid*.js">` or `<link href=…>`

0 commit comments

Comments
 (0)