Skip to main content

api_gateway/
config.rs

1use serde::{Deserialize, Serialize};
2
3fn default_require_auth_by_default() -> bool {
4    true
5}
6
7fn default_body_limit_bytes() -> usize {
8    16 * 1024 * 1024
9}
10
11/// API gateway configuration - reused from `api_gateway` module
12#[derive(Debug, Clone, Deserialize, Serialize, Default)]
13#[serde(deny_unknown_fields)]
14#[allow(clippy::struct_excessive_bools)]
15pub struct ApiGatewayConfig {
16    pub bind_addr: String,
17    #[serde(default)]
18    pub enable_docs: bool,
19    #[serde(default)]
20    pub cors_enabled: bool,
21    /// Optional detailed CORS configuration
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub cors: Option<CorsConfig>,
24
25    /// `OpenAPI` document metadata
26    #[serde(default)]
27    pub openapi: OpenApiConfig,
28
29    /// Global defaults
30    #[serde(default)]
31    pub defaults: Defaults,
32
33    /// Disable authentication and authorization completely.
34    /// When true, middleware automatically injects a default `SecurityContext` for all requests,
35    /// providing access with no tenant filtering.
36    /// This bypasses all tenant isolation and should only be used for single-user on-premise installations.
37    /// Default: false (authentication required via `AuthN` Resolver).
38    #[serde(default)]
39    pub auth_disabled: bool,
40
41    /// If true, routes without explicit security requirement still require authentication (AuthN-only).
42    #[serde(default = "default_require_auth_by_default")]
43    pub require_auth_by_default: bool,
44
45    /// Optional URL path prefix prepended to every route (e.g. `"/cf"` → `/cf/users`).
46    /// Must start with a leading slash; trailing slashes are stripped automatically.
47    /// Empty string (the default) means no prefix.
48    #[serde(default)]
49    pub prefix_path: String,
50
51    /// HTTP metrics settings.
52    #[serde(default)]
53    pub metrics: MetricsConfig,
54}
55
56#[derive(Debug, Clone, Deserialize, Serialize)]
57#[serde(deny_unknown_fields, default)]
58pub struct Defaults {
59    /// Fallback rate limit when operation does not specify one
60    pub rate_limit: RateLimitDefaults,
61    /// Global request body size limit in bytes
62    pub body_limit_bytes: usize,
63}
64
65impl Default for Defaults {
66    fn default() -> Self {
67        Self {
68            rate_limit: RateLimitDefaults::default(),
69            body_limit_bytes: default_body_limit_bytes(),
70        }
71    }
72}
73
74#[derive(Debug, Clone, Deserialize, Serialize)]
75#[serde(deny_unknown_fields, default)]
76pub struct RateLimitDefaults {
77    pub rps: u32,
78    pub burst: u32,
79    pub in_flight: u32,
80}
81
82impl Default for RateLimitDefaults {
83    fn default() -> Self {
84        Self {
85            rps: 50,
86            burst: 100,
87            in_flight: 64,
88        }
89    }
90}
91
92#[derive(Debug, Clone, Deserialize, Serialize)]
93#[serde(deny_unknown_fields, default)]
94pub struct CorsConfig {
95    /// Allowed origins: `["*"]` means any
96    pub allowed_origins: Vec<String>,
97    /// Allowed HTTP methods, e.g. `["GET","POST","OPTIONS","PUT","DELETE","PATCH"]`
98    pub allowed_methods: Vec<String>,
99    /// Allowed request headers; `["*"]` means any
100    pub allowed_headers: Vec<String>,
101    /// Whether to allow credentials
102    pub allow_credentials: bool,
103    /// Max age for preflight caching in seconds
104    pub max_age_seconds: u64,
105}
106
107impl Default for CorsConfig {
108    fn default() -> Self {
109        Self {
110            allowed_origins: vec!["*".to_owned()],
111            allowed_methods: vec![
112                "GET".to_owned(),
113                "POST".to_owned(),
114                "PUT".to_owned(),
115                "PATCH".to_owned(),
116                "DELETE".to_owned(),
117                "OPTIONS".to_owned(),
118            ],
119            allowed_headers: vec!["*".to_owned()],
120            allow_credentials: false,
121            max_age_seconds: 600,
122        }
123    }
124}
125
126/// HTTP metrics configuration.
127#[derive(Debug, Clone, Deserialize, Serialize, Default)]
128#[serde(deny_unknown_fields, default)]
129pub struct MetricsConfig {
130    /// Optional prefix for HTTP metrics instrument names.
131    ///
132    /// When set, metric names become `{prefix}.http.server.request.duration`
133    /// and `{prefix}.http.server.active_requests` instead of the default
134    /// OpenTelemetry semantic convention names.
135    ///
136    /// Empty string (the default) means no prefix — standard `OTel` names are used.
137    pub prefix: String,
138}
139
140/// `OpenAPI` document metadata configuration
141#[derive(Debug, Clone, Deserialize, Serialize)]
142#[serde(deny_unknown_fields, default)]
143pub struct OpenApiConfig {
144    /// API title shown in `OpenAPI` documentation
145    pub title: String,
146    /// API version
147    pub version: String,
148    /// API description (optional)
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub description: Option<String>,
151}
152
153impl Default for OpenApiConfig {
154    fn default() -> Self {
155        Self {
156            title: "API Documentation".to_owned(),
157            version: "0.1.0".to_owned(),
158            description: None,
159        }
160    }
161}