Skip to main content

posthog_rs/
endpoints.rs

1use std::fmt;
2
3/// US ingestion endpoint
4pub const US_INGESTION_ENDPOINT: &str = "https://us.i.posthog.com";
5
6/// EU ingestion endpoint  
7pub const EU_INGESTION_ENDPOINT: &str = "https://eu.i.posthog.com";
8
9/// Default host (US by default)
10pub const DEFAULT_HOST: &str = US_INGESTION_ENDPOINT;
11
12/// API endpoints for different operations
13#[derive(Debug, Clone)]
14pub enum Endpoint {
15    /// Event capture endpoint
16    Capture,
17    /// Batch event capture endpoint
18    Batch,
19    /// Feature flags endpoint
20    Flags,
21    /// Local evaluation endpoint
22    LocalEvaluation,
23}
24
25impl Endpoint {
26    /// Get the path for this endpoint
27    pub fn path(&self) -> &str {
28        match self {
29            Endpoint::Capture => "/i/v0/e/",
30            Endpoint::Batch => "/batch/",
31            Endpoint::Flags => "/flags/?v=2",
32            Endpoint::LocalEvaluation => "/flags/definitions/?send_cohorts",
33        }
34    }
35}
36
37impl fmt::Display for Endpoint {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        write!(f, "{}", self.path())
40    }
41}
42
43/// Manages PostHog API endpoints and host configuration
44#[derive(Debug, Clone)]
45pub struct EndpointManager {
46    base_host: String,
47    raw_host: String,
48}
49
50impl EndpointManager {
51    /// Create a new endpoint manager with the given normalized host
52    pub fn new(host: String) -> Self {
53        let base_host = Self::determine_server_host(&host);
54
55        Self {
56            base_host,
57            raw_host: host,
58        }
59    }
60
61    /// Determine the actual server host based on the provided normalized host
62    /// Similar to posthog-python's determine_server_host function
63    pub fn determine_server_host(host: &str) -> String {
64        let trimmed_host = host.trim_end_matches('/');
65
66        match trimmed_host {
67            "https://app.posthog.com" | "https://us.posthog.com" => {
68                US_INGESTION_ENDPOINT.to_string()
69            }
70            "https://eu.posthog.com" => EU_INGESTION_ENDPOINT.to_string(),
71            _ => trimmed_host.to_string(),
72        }
73    }
74
75    /// Get the base host URL (for constructing endpoints)
76    pub fn base_host(&self) -> &str {
77        &self.base_host
78    }
79
80    /// Get the raw host (as provided by the user, used for session replay URLs)
81    pub fn raw_host(&self) -> &str {
82        &self.raw_host
83    }
84
85    /// Build a full URL for a given endpoint
86    pub fn build_url(&self, endpoint: Endpoint) -> String {
87        format!(
88            "{}{}",
89            self.base_host.trim_end_matches('/'),
90            endpoint.path()
91        )
92    }
93
94    /// Build a URL with a custom path
95    pub fn build_custom_url(&self, path: &str) -> String {
96        let normalized_path = if path.starts_with('/') {
97            path.to_string()
98        } else {
99            format!("/{path}")
100        };
101        format!(
102            "{}{}",
103            self.base_host.trim_end_matches('/'),
104            normalized_path
105        )
106    }
107
108    /// Build the local evaluation URL with a token
109    pub fn build_local_eval_url(&self, token: &str) -> String {
110        format!(
111            "{}/flags/definitions/?token={}&send_cohorts",
112            self.base_host.trim_end_matches('/'),
113            token
114        )
115    }
116
117    /// Get the base host for API operations (without the path)
118    pub fn api_host(&self) -> String {
119        self.base_host.trim_end_matches('/').to_string()
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn test_determine_server_host() {
129        assert_eq!(
130            EndpointManager::determine_server_host("https://app.posthog.com"),
131            US_INGESTION_ENDPOINT
132        );
133
134        assert_eq!(
135            EndpointManager::determine_server_host("https://us.posthog.com"),
136            US_INGESTION_ENDPOINT
137        );
138
139        assert_eq!(
140            EndpointManager::determine_server_host("https://eu.posthog.com"),
141            EU_INGESTION_ENDPOINT
142        );
143
144        assert_eq!(
145            EndpointManager::determine_server_host("https://custom.domain.com"),
146            "https://custom.domain.com"
147        );
148
149        assert_eq!(
150            EndpointManager::determine_server_host("https://eu.posthog.com/"),
151            EU_INGESTION_ENDPOINT
152        );
153    }
154
155    #[test]
156    fn test_build_url() {
157        let manager = EndpointManager::new(DEFAULT_HOST.to_string());
158
159        assert_eq!(
160            manager.build_url(Endpoint::Capture),
161            format!("{}/i/v0/e/", US_INGESTION_ENDPOINT)
162        );
163
164        assert_eq!(
165            manager.build_url(Endpoint::Flags),
166            format!("{}/flags/?v=2", US_INGESTION_ENDPOINT)
167        );
168    }
169
170    #[test]
171    fn test_build_custom_url() {
172        let manager = EndpointManager::new("https://custom.com/".to_string());
173
174        assert_eq!(
175            manager.build_custom_url("/api/test"),
176            "https://custom.com/api/test"
177        );
178
179        assert_eq!(
180            manager.build_custom_url("api/test"),
181            "https://custom.com/api/test"
182        );
183    }
184}