rust_microservice/settings.rs
1//! The server behavior is fully driven by a YAML configuration file. This file defines network
2//! settings, security providers, data sources, and observability integrations used at runtime.
3//!
4//! The configuration is loaded during application startup and applied automatically by the framework.
5//!
6//! ## Server
7//!
8//! Defines how the HTTP service is exposed and how it interacts with the runtime environment.
9//!
10//! | Field | Description |
11//! | --------------------- | ------------------------------------------------------------------------- |
12//! | `host` | Network interface where the server binds. |
13//! | `port` | Main HTTP port used by the API. |
14//! | `health-check-port` | Dedicated port exposing the health endpoint. |
15//! | `use-docker-compose` | Enables orchestration of dependencies via Docker Compose. |
16//! | `docker-compose-file` | Path to the Docker Compose definition used when orchestration is enabled. |
17//!
18//! ## CORS
19//!
20//! Controls cross-origin access policies.
21//!
22//! | Field | Description |
23//! | ------------------------- | ------------------------------------------------------------------ |
24//! | `max-age` | Duration (seconds) browsers cache preflight responses. |
25//! | `allow-credentials` | Allows cookies and authorization headers in cross-origin requests. |
26//! | `allowed-methods` | HTTP methods allowed for cross-origin calls. |
27//! | `allowed-headers` | Headers accepted from clients. |
28//! | `allowed-origins_pattern` | Comma-separated list of allowed origin patterns. |
29//!
30//! ## Security — OAuth2 / OpenID Connect
31//!
32//! Enables authentication and token validation using an OAuth2 provider.
33//!
34//! | Field | Description |
35//! | ------------------------- | ------------------------------------------------------------------ |
36//! | `enabled` | Activates OAuth2 protection for secured endpoints. |
37//! | `load-from-discovery-url` | Automatically loads provider metadata from the discovery endpoint. |
38//! | `discovery-url` | OpenID Provider discovery document. |
39//! | `issuer-uri` | Expected token issuer identifier. |
40//! | `jwks-uri` | JSON Web Key Set endpoint used to validate tokens. |
41//! | `token-uri` | Endpoint for obtaining access tokens. |
42//! | `authorization-uri` | Authorization endpoint for login flows. |
43//! | `introspection-uri` | Endpoint for validating opaque tokens. |
44//! | `user_info-uri` | Endpoint returning authenticated user claims. |
45//! | `end_session-uri` | Logout endpoint for session termination. |
46//!
47//! ## OAuth2 Client
48//!
49//! Credentials used by the server when interacting with the identity provider.
50//!
51//! | Field | Description |
52//! | -------- | --------------------------------------- |
53//! | `id` | OAuth2 client identifier. |
54//! | `secret` | OAuth2 client secret. |
55//! | `scope` | Requested scopes during authentication. |
56//!
57//!
58//! ## JWKS
59//!
60//! Defines local JSON Web Keys used for token signing or validation.
61//!
62//! Each key entry contains:
63//!
64//! - kid — Key identifier
65//! - kty — Key type
66//! - alg — Signing algorithm
67//! - use — Key usage
68//! - e — Public exponent
69//! - n — RSA modulus
70//! - x5c — X.509 certificate chain
71//!
72//! This section is typically used when keys are managed internally or cached locally.
73//!
74//! ## Data Sources
75//!
76//! ### *Redis*
77//!
78//! Configuration for distributed cache and key-value storage.
79//!
80//! | Field | Description |
81//! | ---------------------- | ----------------------------------------------- |
82//! | `enabled` | Enables Redis integration. |
83//! | `host` / `port` | Connection settings. |
84//! | `client-type` | Redis client implementation. |
85//! | `lettuce.pool` | Connection pool configuration. |
86//! | `repositories.enabled` | Enables repository abstraction backed by Redis. |
87//!
88//!
89//! ### *Relational Databases*
90//!
91//! Defines a list of database connections used by the application.
92//!
93//! Each database entry supports:
94//!
95//! - Connection pooling configuration
96//! - Timeouts and lifecycle settings
97//! - SQL logging control
98//! - Independent enable/disable toggle
99//!
100//! This allows multiple data sources (e.g., API DB, job processing DB) to coexist in the same runtime.
101//!
102//! | Field | Description |
103//! | ---------------- | ------------------------------------------------------------------------------------------------- |
104//! | `name` | Logical name of the database connection used by the server. |
105//! | `enabled` | Enables or disables this database configuration. When `false`, the connection is not initialized. |
106//! | `url` | Database connection string used to establish the connection. |
107//! | `min-pool-size` | Minimum number of connections maintained in the pool. |
108//! | `max-pool-size` | Maximum number of connections allowed in the pool. |
109//! | `logging` | Enables query and connection logging for this database. |
110//! | `aquire-timeout` | Maximum time (in seconds) to wait when acquiring a connection from the pool. |
111//! | `max-lifetime` | Maximum lifetime (in minutes) of |
112//!
113//! > Important: The framework currently supports only SQLite, PostgreSQL, MySQL, MariaDB, and
114//! > Microsoft SQL Server databases.
115//!
116//! ### *BigQuery Database Connection*
117//!
118//! This section defines the configuration parameters required to establish a secure connection
119//! to Google BigQuery, the fully managed data warehouse provided by Google. These settings allow
120//! the server to authenticate, select the target project and dataset, and control execution
121//! behavior for queries. .
122//!
123//! | Field | Description |
124//! | -------------- | ------------------------------------------- |
125//! | `enabled` | Enables BigQuery access. |
126//! | `print-tables` | Logs available tables during startup. |
127//! | `region` | Dataset region. |
128//! | `project` | Google Cloud project identifier. |
129//! | `credential` | Base64-encoded service account credentials. |
130//! | `dataset` | List of datasets used by the application. |
131//!
132//!
133//! ## Metrics
134//!
135//! Controls application observability and monitoring integration.
136//!
137//! | Field | Description |
138//! | ---------- | --------------------------------------- |
139//! | `enabled` | Enables metrics collection. |
140//! | `app-name` | Identifier used when exporting metrics. |
141//!
142//!
143//! ## Runtime Notes
144//!
145//! - Disabled components remain configured but inactive.
146//! - Secrets should be externalized in production environments.
147//! - Configuration values can be overridden via environment variables or CLI parameters.
148//! - The configuration is validated during server startup.
149//!
150use config::{Case, Config, ConfigError, Environment, File, FileFormat};
151use jsonwebtoken::jwk::{Jwk, JwkSet};
152#[allow(unused)]
153use log::LevelFilter;
154use serde::Deserialize;
155
156/// Configuration for enabling or disabling data repositories.
157///
158/// This structure is usually used to control whether repository
159/// layers backed by Redis or other data sources should be enabled.
160#[derive(Debug, Deserialize, Clone)]
161#[serde(rename_all = "kebab-case")]
162pub struct Repositories {
163 /// Enables or disables repositories.
164 pub enabled: Option<bool>,
165}
166
167/// Connection pool configuration.
168///
169/// Defines limits and behavior for resource pooling,
170/// such as database or Redis connections.
171#[derive(Debug, Deserialize, Clone)]
172#[serde(rename_all = "kebab-case")]
173pub struct Pool {
174 /// Enables or disables the connection pool.
175 pub enabled: Option<bool>,
176
177 /// Minimum number of idle connections kept in the pool.
178 pub min_idle: Option<usize>,
179
180 /// Maximum number of idle connections allowed.
181 pub max_idle: Option<usize>,
182
183 /// Maximum number of active connections allowed.
184 pub max_active: Option<usize>,
185}
186
187/// Lettuce client configuration.
188///
189/// Represents advanced Redis client settings,
190/// including connection pool configuration.
191#[derive(Debug, Deserialize, Clone)]
192#[serde(rename_all = "kebab-case")]
193pub struct Lettuce {
194 /// Connection pool configuration for the Lettuce client.
195 pub pool: Option<Pool>,
196}
197
198/// Redis configuration.
199///
200/// Defines connection parameters and client behavior
201/// for Redis-based integrations.
202#[derive(Debug, Deserialize, Clone)]
203#[serde(rename_all = "kebab-case")]
204pub struct Redis {
205 /// Redis server host.
206 pub host: Option<String>,
207
208 /// Redis server port.
209 pub port: Option<u16>,
210
211 /// Type of Redis client implementation.
212 pub client_type: Option<String>,
213
214 /// Lettuce client specific configuration.
215 pub lettuce: Option<Lettuce>,
216
217 /// Repository configuration related to Redis usage.
218 pub repositories: Option<Repositories>,
219}
220
221/// Relational database configuration.
222///
223/// Controls connection details, pooling behavior,
224/// timeouts, and logging options.
225#[derive(Debug, Deserialize, Clone)]
226#[serde(rename_all = "kebab-case")]
227pub struct Database {
228 /// Database connection name.
229 pub name: String,
230
231 /// Database connection enabled. Default true.
232 pub enabled: Option<bool>,
233
234 /// Database connection URL.
235 pub url: Option<String>,
236
237 /// Minimum number of connections in the pool.
238 pub min_pool_size: Option<u32>,
239
240 /// Maximum number of connections in the pool.
241 pub max_pool_size: Option<u32>,
242
243 /// Enables or disables database query logging.
244 pub logging: Option<bool>,
245
246 /// Timeout for acquiring a connection from the pool (in seconds).
247 pub aquire_timeout: Option<u64>,
248
249 /// Maximum lifetime of a connection (in seconds).
250 pub max_lifetime: Option<u64>,
251
252 /// Maximum idle time of a connection (in seconds).
253 pub idle_timeout: Option<u64>,
254
255 /// Timeout for establishing a new connection (in seconds).
256 pub connect_timeout: Option<u64>,
257
258 /// Logging level used by the database layer.
259 pub logging_level: Option<String>,
260}
261
262/// Google BigQuery configuration.
263///
264/// Defines access parameters and datasets used
265/// for analytics and data processing.
266#[derive(Debug, Deserialize, Clone)]
267#[serde(rename_all = "kebab-case")]
268pub struct BigQuery {
269 /// BigQuery connection enabled. Defaults true.
270 pub enabled: Option<bool>,
271
272 /// Enables or disables printing available tables.
273 pub print_tables: Option<bool>,
274
275 /// BigQuery region.
276 pub region: Option<String>,
277
278 /// Google Cloud project identifier.
279 pub project: Option<String>,
280
281 /// Path or identifier for the credential file.
282 pub credential: Option<String>,
283
284 /// List of datasets available for querying.
285 pub dataset: Option<Vec<String>>,
286}
287
288/// Data layer configuration.
289///
290/// Groups all data-related configurations,
291/// such as Redis, BigQuery, and relational databases.
292#[derive(Debug, Deserialize, Clone)]
293#[serde(rename_all = "kebab-case")]
294pub struct Data {
295 /// Enables or disables redis connection.
296 pub enabled: Option<bool>,
297
298 /// Redis configuration.
299 pub redis: Option<Redis>,
300
301 /// BigQuery configuration.
302 pub bigquery: Option<BigQuery>,
303
304 /// Relational database configuration.
305 pub databases: Option<Vec<Database>>,
306}
307
308/// CORS (Cross-Origin Resource Sharing) configuration.
309///
310/// Controls how the server handles cross-origin HTTP requests.
311#[derive(Debug, Deserialize, Clone)]
312#[serde(rename_all = "kebab-case")]
313pub struct Cors {
314 /// Maximum cache age for CORS preflight requests (in seconds).
315 pub max_age: Option<u32>,
316
317 /// Indicates whether credentials are allowed.
318 pub allow_credentials: Option<bool>,
319
320 /// Allowed HTTP methods.
321 pub allowed_methods: Option<String>,
322
323 /// Allowed HTTP headers.
324 pub allowed_headers: Option<String>,
325
326 /// Allowed origin patterns.
327 pub allowed_origins_pattern: Option<String>,
328}
329
330/// Server configuration.
331///
332/// Defines network, runtime, and deployment-related settings.
333#[derive(Debug, Deserialize, Clone)]
334#[serde(rename_all = "kebab-case")]
335pub struct Server {
336 /// Server host address.
337 pub host: Option<String>,
338
339 /// Main server port.
340 pub port: u16,
341
342 /// Port used for health check endpoints.
343 pub health_check_port: u16,
344
345 /// Number of worker threads.
346 pub workers: Option<usize>,
347
348 /// Number of worker threads for health checks.
349 pub health_check_workers: Option<usize>,
350
351 /// Indicates whether Docker Compose is used.
352 pub use_docker_compose: Option<bool>,
353
354 /// Path to the Docker Compose file.
355 pub docker_compose_file: Option<String>,
356
357 /// CORS configuration.
358 pub cors: Option<Cors>,
359}
360
361/// Metrics configuration.
362///
363/// Controls application metrics exposure and identification.
364#[derive(Debug, Deserialize, Clone)]
365#[serde(rename_all = "kebab-case")]
366pub struct Metrics {
367 /// Enables or disables metrics collection.
368 pub enabled: Option<bool>,
369
370 /// Application name used in metrics labels.
371 pub app_name: Option<String>,
372}
373
374/// OAuth2 configuration.
375///
376/// Controls authentication and authorization settings.
377#[derive(Debug, Deserialize, Clone)]
378#[serde(rename_all = "kebab-case")]
379pub struct OAuth2Configuration {
380 /// Enables or disables OAuth2 integration.
381 pub enabled: Option<bool>,
382
383 /// Enables or disables automatic OAuth2 discovery.
384 pub discovery_enabled: Option<bool>,
385
386 /// OAuth2 discovery URL for automatic configuration.
387 #[serde(alias = "discovery_endpoint")]
388 pub discovery_url: Option<String>,
389
390 /// OAuth2 configuration issuer URL.
391 #[serde(alias = "issuer", alias = "issuer_endpoint")]
392 pub issuer_uri: Option<String>,
393
394 /// OAuth2 configuration JSON Web Key Set URI.
395 #[serde(alias = "jwks_endpoint", alias = "jwks_uri")]
396 pub jwks_uri: Option<String>,
397
398 /// OAuth2 configuration token endpoint URI.
399 #[serde(alias = "token_endpoint")]
400 pub token_uri: Option<String>,
401
402 /// OAuth2 configuration authorization endpoint URI.
403 #[serde(alias = "authorization_endpoint")]
404 pub authorization_uri: Option<String>,
405
406 /// OAuth2 configuration introspection endpoint URI.
407 #[serde(alias = "introspection_endpoint")]
408 pub introspection_uri: Option<String>,
409
410 /// OAuth2 configuration user info endpoint URI.
411 #[serde(alias = "userinfo_endpoint")]
412 pub user_info_uri: Option<String>,
413
414 /// OAuth2 configuration end session endpoint URI.
415 #[serde(alias = "end_session_endpoint")]
416 pub end_session_uri: Option<String>,
417
418 /// OAuth2 client configuration.
419 pub client: Option<OAuth2Client>,
420
421 /// OAuth2 JSON Web Key Set. This list of keys is used to validate tokens.
422 pub jwks: Option<JwkSet>,
423}
424
425/// OAuth2 client configuration.
426
427#[derive(Debug, Deserialize, Clone)]
428#[serde(rename_all = "kebab-case")]
429pub struct OAuth2Client {
430 /// OAuth2 client ID.
431 pub id: Option<String>,
432
433 /// OAuth2 client secret.
434 pub secret: Option<String>,
435
436 /// OAuth2 client scopes.
437 pub scope: Option<String>,
438}
439
440/// Server security configuration.
441///
442/// This structure aggregates all security-related settings.
443#[derive(Debug, Deserialize, Clone)]
444#[serde(rename_all = "kebab-case")]
445pub struct Security {
446 /// OAuth2 configuration.
447 pub oauth2: Option<OAuth2Configuration>,
448}
449
450/// Global application settings.
451///
452/// Root configuration structure that aggregates
453/// server, data, and metrics configurations.
454#[derive(Debug, Deserialize, Clone)]
455#[serde(rename_all = "kebab-case")]
456pub struct Settings {
457 /// Server configuration.
458 pub server: Option<Server>,
459
460 /// Data layer configuration.
461 pub data: Option<Data>,
462
463 /// Metrics configuration.
464 pub metrics: Option<Metrics>,
465
466 /// Security configuration.
467 pub security: Option<Security>,
468}
469
470impl Settings {
471 /// Loads the application settings from a configuration file.
472 ///
473 /// This function reads the configuration from the specified file path,
474 /// deserializes it into the `Settings` structure, and returns it.
475 ///
476 /// # Arguments
477 ///
478 /// * `config_path` - A string slice that holds the path to the configuration file.
479 ///
480 /// # Returns
481 ///
482 /// * `Result<Settings, ConfigError>` - The loaded settings or an error if loading fails.
483 pub fn new(config_path: &str) -> Result<Self> {
484 let mut builder = Config::builder().add_source(File::new(config_path, FileFormat::Yaml));
485
486 builder =
487 builder.add_source(Environment::with_convert_case(Case::UpperSnake).separator("_"));
488
489 let config = builder.build()?;
490 config.try_deserialize::<Settings>()
491 }
492
493 /// Returns the OAuth2 configuration object if available.
494 ///
495 /// # Returns
496 ///
497 /// * `Option<OAuth2Configuration>` - The OAuth2 configuration if present, `None` otherwise.
498 pub fn get_oauth2_config(&self) -> Option<OAuth2Configuration> {
499 self.security.as_ref()?.oauth2.clone()
500 }
501
502 /// Returns a JWK (JSON Web Key) object if available for the given kid.
503 ///
504 /// # Arguments
505 ///
506 /// * `kid` - A string slice that holds the key ID of the JWK object.
507 ///
508 /// # Returns
509 ///
510 /// * `Option<Jwk>` - The JWK object if present, `None` otherwise.
511 pub fn get_auth2_public_key(&self, kid: &str) -> Option<Jwk> {
512 self.security
513 .as_ref()?
514 .oauth2
515 .as_ref()?
516 .jwks
517 .as_ref()?
518 .find(kid)
519 .cloned()
520 }
521
522 /// Returns the OAuth2 token endpoint URL if available.
523 ///
524 /// # Returns
525 ///
526 /// * `Option<String>` - The OAuth2 token endpoint URL if present, `None` otherwise.
527 pub fn get_auth2_token_url(&self) -> Option<String> {
528 self.security
529 .as_ref()?
530 .oauth2
531 .as_ref()?
532 .token_uri
533 .as_ref()
534 .cloned()
535 }
536}
537
538/// A type alias for a `Result` with the `ConfigError` error type.
539pub type Result<T, E = ConfigError> = std::result::Result<T, E>;