server/utils/env.rs
1//! Environment variable utilities for safe and validated access.
2//!
3//! This module provides utilities for safely accessing environment variables
4//! with proper validation and error handling. It ensures that environment
5//! variables are not only present but also contain valid, non-empty values.
6
7use thiserror::Error;
8
9/// Errors that can occur when accessing environment variables.
10///
11/// Provides detailed error information for different failure scenarios
12/// when working with environment variables, including missing variables,
13/// encoding issues, and empty values.
14#[derive(Debug, Error)]
15pub enum EnvVarError {
16 /// Environment variable is not set
17 #[error(
18 "Environment variable '{name}' not found. Please set this variable in your .env file or environment."
19 )]
20 NotFound { name: String },
21
22 /// Environment variable contains invalid UTF-8 characters
23 #[error(
24 "Environment variable '{name}' contains invalid UTF-8 characters. Please check the value."
25 )]
26 InvalidUtf8 { name: String },
27
28 /// Environment variable is set but contains only whitespace or is empty
29 #[error("Environment variable '{name}' is empty. Please provide a valid value.")]
30 Empty { name: String },
31}
32
33/// Utility functions for safe environment variable handling.
34///
35/// Provides methods for safely accessing environment variables with proper
36/// validation and error handling. All methods trim whitespace and validate
37/// that values are not empty.
38///
39/// # Examples
40///
41/// ```no_run
42/// use quetty_server::utils::EnvUtils;
43///
44/// // Check if a variable exists and has a value
45/// if EnvUtils::has_non_empty_var("DATABASE_URL") {
46/// // Get the validated value
47/// let url = EnvUtils::get_validated_var("DATABASE_URL")?;
48/// println!("Database URL: {}", url);
49/// }
50///
51/// // Get an optional variable
52/// if let Some(debug_level) = EnvUtils::get_optional_var("DEBUG_LEVEL") {
53/// println!("Debug level: {}", debug_level);
54/// }
55/// ```
56pub struct EnvUtils;
57
58impl EnvUtils {
59 /// Checks if an environment variable exists and has a non-empty value.
60 ///
61 /// This method checks both that the variable is set and that it contains
62 /// non-whitespace content after trimming.
63 ///
64 /// # Arguments
65 ///
66 /// * `name` - The name of the environment variable to check
67 ///
68 /// # Returns
69 ///
70 /// `true` if the variable exists and has a non-empty value, `false` otherwise
71 ///
72 /// # Examples
73 ///
74 /// ```no_run
75 /// use quetty_server::utils::EnvUtils;
76 ///
77 /// if EnvUtils::has_non_empty_var("API_KEY") {
78 /// println!("API key is configured");
79 /// } else {
80 /// println!("API key is missing or empty");
81 /// }
82 /// ```
83 pub fn has_non_empty_var(name: &str) -> bool {
84 match std::env::var(name) {
85 Ok(value) => !value.trim().is_empty(),
86 Err(_) => false,
87 }
88 }
89
90 /// Gets an environment variable with validation.
91 ///
92 /// Retrieves the environment variable, trims whitespace, and validates
93 /// that it contains a non-empty value. Returns detailed error information
94 /// if the variable is missing, empty, or contains invalid UTF-8.
95 ///
96 /// # Arguments
97 ///
98 /// * `name` - The name of the environment variable to retrieve
99 ///
100 /// # Returns
101 ///
102 /// The trimmed, validated environment variable value
103 ///
104 /// # Errors
105 ///
106 /// Returns [`EnvVarError`] if:
107 /// - The variable is not set ([`EnvVarError::NotFound`])
108 /// - The variable is empty or contains only whitespace ([`EnvVarError::Empty`])
109 /// - The variable contains invalid UTF-8 ([`EnvVarError::InvalidUtf8`])
110 ///
111 /// # Examples
112 ///
113 /// ```no_run
114 /// use quetty_server::utils::EnvUtils;
115 ///
116 /// match EnvUtils::get_validated_var("DATABASE_URL") {
117 /// Ok(url) => println!("Database URL: {}", url),
118 /// Err(e) => eprintln!("Configuration error: {}", e),
119 /// }
120 /// ```
121 pub fn get_validated_var(name: &str) -> Result<String, EnvVarError> {
122 match std::env::var(name) {
123 Ok(value) => {
124 let trimmed = value.trim();
125 if trimmed.is_empty() {
126 Err(EnvVarError::Empty {
127 name: name.to_string(),
128 })
129 } else {
130 Ok(trimmed.to_string())
131 }
132 }
133 Err(std::env::VarError::NotPresent) => Err(EnvVarError::NotFound {
134 name: name.to_string(),
135 }),
136 Err(std::env::VarError::NotUnicode(_)) => Err(EnvVarError::InvalidUtf8 {
137 name: name.to_string(),
138 }),
139 }
140 }
141
142 /// Gets an optional environment variable.
143 ///
144 /// Returns the validated environment variable value if it exists and is valid,
145 /// or `None` if it's missing, empty, or invalid. This is a convenience method
146 /// for cases where the absence of an environment variable is acceptable.
147 ///
148 /// # Arguments
149 ///
150 /// * `name` - The name of the environment variable to retrieve
151 ///
152 /// # Returns
153 ///
154 /// `Some(value)` if the variable exists and is valid, `None` otherwise
155 ///
156 /// # Examples
157 ///
158 /// ```no_run
159 /// use quetty_server::utils::EnvUtils;
160 ///
161 /// let debug_mode = EnvUtils::get_optional_var("DEBUG_MODE")
162 /// .unwrap_or_else(|| "false".to_string());
163 ///
164 /// if let Some(custom_config) = EnvUtils::get_optional_var("CUSTOM_CONFIG") {
165 /// println!("Using custom config: {}", custom_config);
166 /// } else {
167 /// println!("Using default configuration");
168 /// }
169 /// ```
170 pub fn get_optional_var(name: &str) -> Option<String> {
171 Self::get_validated_var(name).ok()
172 }
173}