### Application Startup with SSM Configuration Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-aws-ssm.md Defines a resource for loading application configuration from SSM and environment variables, then starting the application. ```scala import ciris._ import ciris.http4s.aws.AwsSsmParameters import cats.effect.{IO, Resource} def loadConfig(ssm: AwsSsmParameters[IO]): Resource[IO, AppConfig] = Resource.eval( ( ssm("prod/database/url"), ssm("prod/api/key").secret, env("LOG_LEVEL").default("INFO") ).parTupled.load[IO] ).map { case (dbUrl, apiKey, logLevel) => AppConfig(dbUrl, apiKey, logLevel) } val app = for { ssm <- Resource.eval(AwsSsmParameters[IO](client, provider, region)) config <- loadConfig(ssm) _ <- startApplication(config) } yield () ``` -------------------------------- ### Testing Configuration Errors with ConfigException Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Provides an example of how to test for ConfigException during configuration loading, specifically checking for missing required configuration variables. ```scala import ciris._ import cats.effect.IO import munit.CatsEffectSuite class ConfigTests extends CatsEffectSuite { test("missing required config raises ConfigException") { val config = env("MISSING_VAR").load[IO] assertIO(config.attempt, Left(ConfigError.Missing(...))) } } ``` -------------------------------- ### Load and Use Password with UseOnceSecret Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/use-once-secret.md This example shows how to load a password using `useOnceSecret` and then use it within an effect. The secret is automatically nullified after the `useOnce` block completes. ```scala import ciris._ import cats.effect.IO val program = env("PASSWORD") .as[Array[Char]] .useOnceSecret .evalFlatMap { useOnce => useOnce.useOnce { chars => IO { val password = new String(chars) // Use password for authentication authenticate(password) } } } .load[IO] ``` -------------------------------- ### Equivalent ConfigValue Calls Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Demonstrates that package object functions like `default`, `env`, and `prop` are direct equivalents to their `ConfigValue` counterparts. The `env` and `prop` examples show the underlying `ConfigValue.suspend` logic. ```scala default(5) ConfigValue.default(5) ``` ```scala env("VAR") ConfigValue.suspend { val value = System.getenv("VAR") if (value != null) ConfigValue.loaded(ConfigKey.env("VAR"), value) else ConfigValue.missing(ConfigKey.env("VAR")) } ``` ```scala prop("name") ConfigValue.suspend { val value = System.getProperty("name") if (value != null) ConfigValue.loaded(ConfigKey.prop("name"), value) else ConfigValue.missing(ConfigKey.prop("name")) } ``` -------------------------------- ### Handle Optional Configuration Values Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-value.md Use `.option` to get an `Option[A]` from a configuration value. This returns `None` if the value is missing. ```scala val apiKey = env("API_KEY").option // ConfigValue[F, Option[String]] ``` -------------------------------- ### Get ConfigKey Description Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Retrieves the human-readable description of the configuration source from a ConfigKey. ```scala val key = ConfigKey.env("DATABASE_URL") println(key.description) // Output: environment variable DATABASE_URL ``` -------------------------------- ### Single-Access Guarantee Example Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/use-once-secret.md This snippet illustrates the single-access guarantee. The first `useOnce` call succeeds, but the subsequent attempt to use the same `UseOnceSecret` instance fails, throwing an `IllegalStateException`. ```scala UseOnceSecret[IO](Array('p', 'w', 'd')).flatMap { useOnce => useOnce.useOnce { chars => IO.println(new String(chars)) // Works: prints "pwd" } >> useOnce.useOnce { _ => IO.println("Again") // Fails: IllegalStateException } } ``` -------------------------------- ### Parsing IP Addresses with Ciris and http4s Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Shows how to parse environment variables into `IpAddress` types using Ciris and http4s integration. It includes examples for both IPv4 and IPv6 addresses. ```scala import ciris._ import ciris.http4s._ import com.comcast.ip4s.IpAddress env("SERVER_IP").as[IpAddress].attempt[IO].unsafeRunSync() // IPv4: // Right(IpAddress(192.168.1.1)) // IPv6: // Right(IpAddress(2001:db8::1)) ``` -------------------------------- ### Validating Port Numbers with Port Type Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Illustrates the automatic validation of port numbers provided by the `Port` type from `com.comcast.ip4s`. It shows examples of valid and invalid port strings. ```scala import com.comcast.ip4s.Port Port.fromString("0") // Port(0) - OK (ephemeral/dynamic) Port.fromString("8080") // Port(8080) - OK Port.fromString("65535") // Port(65535) - OK (maximum) Port.fromString("65536") // None - Out of range Port.fromString("-1") // None - Invalid ``` -------------------------------- ### Application Configuration with Refined Types Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-refined.md Define a case class for your application configuration, using Refined types for fields that require specific constraints (e.g., non-empty strings, positive integers). This example demonstrates loading multiple configuration values, providing defaults, and combining them into the configuration object using `parMapN`. ```scala import ciris._ import ciris.refined._ import eu.timepit.refined.types.numeric.PosInt import eu.timepit.refined.types.string.NonEmptyString import cats.syntax.all._ case class AppConfig( appName: NonEmptyString, port: PosInt, maxConnections: PosInt ) val config = ( env("APP_NAME").as[NonEmptyString], env("PORT").as[PosInt].default(8080), env("MAX_CONNECTIONS").as[PosInt].default(100) ).parMapN(AppConfig.apply).load[IO] ``` -------------------------------- ### Handle Validation Errors with Attempt Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-refined.md Use the `.attempt` method to capture configuration loading and validation errors as an `Either` type. This allows for explicit error handling when a value fails to decode or validate against its Refined type. The example shows how to inspect the `ConfigError` for details. ```scala import ciris._ import ciris.refined._ import eu.timepit.refined.types.numeric.PosInt env("PORT").as[PosInt].attempt[IO].unsafeRunSync() // If PORT="0" (invalid for PosInt): // Left(ConfigError(PosInt cannot be decoded: 0 is not > 0)) // If PORT="-5": // Left(ConfigError(PosInt cannot be decoded: -5 is not > 0)) ``` -------------------------------- ### Good Configuration Loading Pattern Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Illustrates a recommended approach for loading configuration, establishing clear precedence for environment variables and properties, providing a default for non-critical settings, marking sensitive keys, and applying type transformations early. This pattern ensures robustness and security. ```scala // Good: Clear precedence, appropriate defaults val config = ( env("ENVIRONMENT").or(prop("environment")).default("dev"), env("API_KEY").secret, env("MAX_CONNECTIONS").as[Int].default(100) ).parTupled.load[IO] ``` -------------------------------- ### Defaulting Host and Port for Localhost Binding Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Demonstrates how to configure default values for host and port using `env().as[Type].default()` for local development scenarios. It uses `Host.loopback` and a default port. ```scala import ciris._ import ciris.http4s._ import com.comcast.ip4s.Host val localConfig = ( env("SERVER_HOST").as[Host].default(Host.loopback), env("SERVER_PORT").as[Int].default(8080) ).parMapN { (host, port) => (host, port) } ``` -------------------------------- ### Calculate Secret Hash Manually Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Example of how to manually calculate the short hash of a secret value using standard command-line tools. ```bash $ echo -n "RacrqvWjuu4KVmnTG9b6xyZMTP7jnX" | sha1sum | head -c 7 0a7425a ``` -------------------------------- ### Configure Server Host and Port Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Load server host and port from environment variables. Requires `SERVER_HOST` and `SERVER_PORT` to be set. ```scala import ciris._ import ciris.http4s._ import com.comcast.ip4s.Host import org.http4s.Uri case class ServerConfig( host: Host, port: Int ) val config = ( env("SERVER_HOST").as[Host], env("SERVER_PORT").as[Int] ).parMapN(ServerConfig.apply) ``` -------------------------------- ### Specify Effect Type and Covary Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Explicitly define the effect type for a `ConfigValue` or use `covary` to fix the effect type, for example, to `cats.effect.IO`. ```scala import cats.effect.IO port: ConfigValue[IO, Int] port.covary[IO] ``` -------------------------------- ### Manage Configuration Loading as a Resource Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-value.md Use `.resource[G]` to obtain a `Resource` that manages the acquisition and release of configuration values. Useful for resources like file handles. ```scala val result = env("PORT").as[Int].resource[IO].use { port => IO.println(s"Using port $port") } ``` -------------------------------- ### Application Startup Configuration Loading Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Shows a common pattern for loading application configuration using Ciris, including environment variables for database URL, API port, and debug mode. If any configuration is missing or invalid, ConfigException is thrown. ```scala import ciris._ import cats.effect.IO import cats.effect.kernel.Resource def loadConfig: Resource[IO, AppConfig] = Resource.eval( ( env("DATABASE_URL"), env("API_PORT").as[Int], env("DEBUG_MODE").as[Boolean].default(false) ).parTupled.load[IO] ).map { case (dbUrl, port, debug) => AppConfig(dbUrl, port, debug) } // If any configuration is missing or invalid, ConfigException is thrown val app = loadConfig.use { config => startApplication(config) } ``` -------------------------------- ### ConfigKey Rendering with Cats Show Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Shows how to render a ConfigKey as a string using Cats' Show type class, providing a formatted representation. ```scala import cats.Show val key = ConfigKey.prop("server.port") println(key.show) // Output: ConfigKey(system property server.port) ``` -------------------------------- ### Load Configuration with Fallbacks Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Use `alt` to specify an alternative configuration that will be considered even if the primary configuration is partially loaded. This differs from `or`, which only considers fallbacks if the primary configuration is entirely missing. ```scala dev.alt(prod) ``` -------------------------------- ### Load Configuration from System Property Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Use `prop` to load configuration values from system properties. The property name is provided as a string argument. ```scala import ciris._ val dbUrl = prop("database.url") val port = prop("server.port").as[Int] ``` -------------------------------- ### Configure String-Valued API Version Enum Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-enumeratum.md Configures the API version from the `API_VERSION` environment variable, defaulting to `ApiVersion.V3`. This example uses `stringValueEnumDecoder` for enums where entries have a string value. ```scala import ciris._ import enumeratum.{StringEnum, StringEnumEntry} import enumeratum.values.CirisValueEnum._ sealed abstract class ApiVersion(val value: String) extends StringEnumEntry object ApiVersion extends StringEnum[ApiVersion] { case object V1 extends ApiVersion("v1") case object V2 extends ApiVersion("v2") case object V3 extends ApiVersion("v3") val values = findValues } val apiVersion = env("API_VERSION") .as(stringValueEnumDecoder(ApiVersion)) .default(ApiVersion.V3) .load[IO] ``` -------------------------------- ### Load Basic Configuration from Environment Variables Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Loads configuration values from environment variables, specifying types and default values. Use this for standard application settings. ```scala import ciris._ val config = (env("APP_NAME"), env("PORT").as[Int].default(8080), env("DEBUG").as[Boolean].default(false) ).parTupled.load[IO] ``` -------------------------------- ### Numeric Refined Types Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-refined.md Examples of decoding configuration values into common numeric Refined types like positive integers, non-negative longs, and integers within a specific range. ```scala import eu.timepit.refined.types.numeric._ // Positive (> 0) env("PORT").as[PosInt] env("TIMEOUT").as[PosLong] // Non-negative (>= 0) env("RETRY_COUNT").as[NonNegInt] env("BUFFER_SIZE").as[NonNegLong] ``` ```scala import eu.timepit.refined.api.Refined import eu.timepit.refined.numeric.{Greater, LessThan} // 1-100 inclusive type Percentage = Int Refined (Greater[0] And LessThan[101]) env("RETRY_PERCENTAGE").as[Percentage] ``` -------------------------------- ### Get Full SHA-1 Hash Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/secret.md Returns the complete SHA-1 hash of the secret value in hexadecimal format. The value is hashed based on its Show representation, typically as a UTF-8 encoded string. ```scala val secret = Secret("password") val hash = secret.valueHash // hash == "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" ``` -------------------------------- ### Graceful Degradation with Optional Configuration Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Illustrates how to load an optional configuration value and provide a default if it's not present, preventing exceptions. ```scala import ciris._ import cats.effect.IO val config = env("OPTIONAL_SETTING") .option // Returns None if missing .load[IO] val program = config.map { setting => setting.getOrElse("default-value") } ``` -------------------------------- ### Get formatted error message Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Obtains a formatted string representation of the configuration loading errors. This message includes a header, a list of individual errors, and proper indentation for multi-line messages. ```scala val error = ConfigError("First error").and(ConfigError("Second error")) val exception = ConfigException(error) println(exception.message) ``` -------------------------------- ### Custom Configuration Source Keys Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Demonstrates creating ConfigKeys for custom configuration sources like Consul or AWS Secrets Manager, and associating them with loaded values. ```scala val key = ConfigKey("database URL from Consul") val value = ConfigValue.loaded(key, "postgresql://localhost") val key2 = ConfigKey(s"file '/etc/app/config.yml'") val value2 = ConfigValue.loaded(key2, configContent) val key3 = ConfigKey("AWS Secrets Manager secret: app/db_password") val value3 = ConfigValue.loaded(key3, secretValue) ``` -------------------------------- ### Get message using getMessage() Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Calls the standard Java exception getMessage() method, which returns the same formatted error message as the 'message' property. Useful within standard Java exception handling. ```scala try { throw ConfigException(ConfigError("Failed to load config")) } catch { case e: ConfigException => println(e.getMessage) } ``` -------------------------------- ### Loading Single Configuration Value Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-error.md Demonstrates how to attempt loading a single environment variable and handle potential errors using .attempt. Errors are returned as a Left value. ```scala import ciris._ // Single error env("API_KEY") .attempt[IO] .unsafeRunSync() // Left(ConfigError(...)) ``` -------------------------------- ### Combine Squants with Refined Types Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-squants.md Integrate Squants types with other Ciris integrations, such as refined types, for more complex configuration scenarios. This example loads a non-empty string name and a Time value with a default. ```scala import ciris._ import ciris.squants._ import ciris.refined._ import eu.timepit.refined.types.string.NonEmptyString import squants.time.Time case class AppConfig( name: NonEmptyString, timeout: Time ) val config = ( env("APP_NAME").as[NonEmptyString], env("TIMEOUT").as[Time].default(Time(30, "seconds")) ).parMapN(AppConfig.apply).load[IO] ``` -------------------------------- ### Loading Configuration with ConfigException Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Demonstrates how ConfigException is thrown when required configuration values are missing. Use `attempt` to handle loading failures gracefully. ```scala import ciris._ import cats.effect.IO val config = env("REQUIRED_VALUE") // Throws ConfigException if loading fails val result = config.load[IO].unsafeRunSync() // Throws: ConfigException(ConfigError(...)) // Use attempt to handle gracefully val safe = config.attempt[IO].unsafeRunSync() // Returns: Left(ConfigError(...)) or Right(value) ``` -------------------------------- ### Get Short SHA-1 Hash Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/secret.md Returns the first 7 characters of the SHA-1 hash. This is commonly used for logging identifiers without exposing the actual secret value and is also used by the default toString method. ```scala val secret = Secret("api-key-123") val shortHash = secret.valueShortHash // shortHash == "4a0bb2b" (first 7 chars) secret.toString // "Secret(4a0bb2b)" ``` -------------------------------- ### Creating ConfigValues Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-value.md Demonstrates various ways to create ConfigValue instances, including default values, loaded values, missing values, failed values, and suspending or evaluating effects. ```APIDOC ## ConfigValue.default(value: => A): ConfigValue[Effect, A] ### Description Returns a configuration value with a default value. ### Method `default` ### Parameters - **value** (=> A) - Required - The default value to use. ### Request Example ```scala import ciris._ val maxConnections = default(10) val result: Int = maxConnections.load[IO].unsafeRunSync() // result == 10 ``` ``` ```APIDOC ## ConfigValue.loaded(key: ConfigKey, value: A): ConfigValue[Effect, A] ### Description Returns a successfully loaded configuration value. ### Method `loaded` ### Parameters - **key** (ConfigKey) - Required - The key associated with the loaded value. - **value** (A) - Required - The successfully loaded value. ### Request Example ```scala val key = ConfigKey.env("DATABASE_URL") val value = ConfigValue.loaded(key, "postgresql://localhost") ``` ``` ```APIDOC ## ConfigValue.missing(key: ConfigKey): ConfigValue[Effect, A] ### Description Returns a configuration value that failed because the value was missing. ### Method `missing` ### Parameters - **key** (ConfigKey) - Required - The key for which the value was missing. ### Request Example ```scala val value = ConfigValue.missing(ConfigKey.env("API_KEY")) ``` ``` ```APIDOC ## ConfigValue.failed(error: ConfigError): ConfigValue[Effect, A] ### Description Returns a configuration value that failed with a specified error. ### Method `failed` ### Parameters - **error** (ConfigError) - Required - The error that caused the failure. ### Request Example ```scala val value = ConfigValue.failed(ConfigError("Connection refused")) ``` ``` ```APIDOC ## ConfigValue.suspend(value: => ConfigValue[F, A]): ConfigValue[F, A] ### Description Suspends the creation of a configuration value, deferring its evaluation. ### Method `suspend` ### Parameters - **value** (=> ConfigValue[F, A]) - Required - A by-name parameter for the configuration value to be evaluated later. ### Request Example ```scala val config = ConfigValue.suspend { if (isProduction) productionConfig else devConfig } ``` ``` ```APIDOC ## ConfigValue.eval(value: F[ConfigValue[F, A]]): ConfigValue[F, A] ### Description Creates a configuration value from an effect that produces a `ConfigValue`. ### Method `eval` ### Parameters - **value** (F[ConfigValue[F, A]]) - Required - An effect that yields a `ConfigValue`. ### Request Example ```scala val config = ConfigValue.eval(IO { ConfigValue.loaded(ConfigKey.env("PORT"), "8080") }) ``` ``` ```APIDOC ## ConfigValue.blocking(value: => ConfigValue[F, A]): ConfigValue[F, A] ### Description Creates a configuration value with blocking evaluation. ### Method `blocking` ### Parameters - **value** (=> ConfigValue[F, A]) - Required - A by-name parameter for the configuration value to be evaluated in a blocking manner. ### Request Example ```scala val config = ConfigValue.blocking(loadFromDisk()) ``` ``` ```APIDOC ## ConfigValue.resource(resource: Resource[F, ConfigValue[F, A]]): ConfigValue[F, A] ### Description Creates a configuration value from a `Resource`. ### Method `resource` ### Parameters - **resource** (Resource[F, ConfigValue[F, A]]) - Required - A `Resource` that yields a `ConfigValue`. ### Request Example ```scala val config = ConfigValue.resource( Resource.make(acquireConnection)(_.close).map { conn => ConfigValue.loaded(ConfigKey("database"), conn) } ) ``` ``` ```APIDOC ## ConfigValue.async(k: ...): ConfigValue[F, A] ### Description Creates a configuration value from an async callback. ### Method `async` ### Parameters - **k** - Required - A function that takes a callback and returns an effect. ### Request Example ```scala val config = ConfigValue.async[IO, String] { callback => IO { IO { // In a real scenario, this might be an actual async operation callback(Right(ConfigValue.default("value"))) }.some } } ``` ``` -------------------------------- ### Load Configuration from Environment and System Properties Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/README.md Load configuration values from environment variables and system properties, with a default value if none are found. This is useful for setting up application ports or other common settings. ```scala import ciris._ import cats.effect.IO // Load from environment and system properties val port = env("PORT") .as[Int] .or(prop("server.port")) .or(default(8080)) // Compose multiple values val config = ( env("APP_NAME"), port, env("DEBUG").as[Boolean].default(false) ).parTupled.load[IO] ``` -------------------------------- ### ConfigDecoder for Secret Values Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-decoder.md Demonstrates how to create decoders for sensitive string values wrapped in `Secret`. The first example shows extracting a value from `Secret[String]` and decoding it, while the second shows decoding a string and wrapping it in `Secret[B]`. ```scala val decoder: ConfigDecoder[Secret[String], Int] = ConfigDecoder[String, Int].contramap((s: Secret[String]) => s.value) ``` ```scala val decoder: ConfigDecoder[String, Secret[String]] = implicitly[ConfigDecoder[String, Secret[String]]] ``` -------------------------------- ### Load Multiple Configuration Parameters Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-aws-ssm.md Loads multiple configuration values from both SSM and environment variables, combining them into a tuple. Includes a default value for the PORT environment variable. ```scala import ciris._ import ciris.http4s.aws.AwsSsmParameters import cats.syntax.all._ val ssm = AwsSsmParameters[IO](client, provider, region) val config = ( ssm("prod/db/url"), ssm("prod/api/key"), ssm("prod/jwt/secret"), env("PORT").as[Int].default(8080) ).parTupled.load[IO] ``` -------------------------------- ### Range Validation for Percentage Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-refined.md Implement range validation for numerical configuration values, such as a percentage, using `Refined` with `GreaterEqual` and `LessThan`. This example defines a `Percentage` type for integers between 0 and 100 (inclusive of 0, exclusive of 101) and applies it to a cache TTL setting. ```scala import ciris._ import ciris.refined._ import eu.timepit.refined.api.Refined import eu.timepit.refined.numeric.{Greater, LessThan} // Percentage: 0-100 type Percentage = Int Refined (GreaterEqual[0] And LessThan[101]) val timeout = env("CACHE_TTL_PERCENTAGE") .as[Percentage] .default(80) .load[IO] ``` -------------------------------- ### Encryption Key Management with Use Once Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/use-once-secret.md Load and use an encryption key securely. The `useOnce` method guarantees that the key material is automatically nullified after the encryption operation. ```scala import ciris._ import cats.effect.IO val encryptionKey = env("ENCRYPTION_KEY") .as[Array[Char]] .useOnceSecret val encrypted = encryptionKey.evalMap { keySecret => keySecret.useOnce { keyChars => IO { val key = new String(keyChars) // Encrypt data with key // Key array is nullified after this block encryptData(data, key) } } } ``` -------------------------------- ### Complete Configuration Loading Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Loads a complete configuration object by combining multiple environment variables and properties with fallbacks, defaults, and type conversions. Uses parallel mapping for efficient loading. ```scala import ciris._ import cats.syntax.all._ case class Config( environment: String, databaseUrl: String, port: Int, maxRetries: Int ) val config = ( env("ENVIRONMENT").or(prop("environment")).default("dev"), env("DATABASE_URL").or(prop("db.url")).secret, env("PORT").or(prop("port")).as[Int].default(8080), env("MAX_RETRIES").or(prop("max.retries")).as[Int].default(3) ).parMapN(Config.apply) val result = config.load[IO] ``` -------------------------------- ### ConfigKey Methods Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md ConfigKey provides human-readable descriptions for configuration sources, aiding in error reporting and offering convenient creation methods. ```APIDOC ## ConfigKey ### Description Human-readable descriptions of configuration sources for error reporting. ### Key Methods - `env(name: String)` - `prop(name: String)` - `apply(description: String)` ``` -------------------------------- ### Catching and Logging ConfigException Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Shows how to catch a `ConfigException` during configuration loading and log a custom message before re-raising the error. ```scala import ciris._ import cats.effect.IO val config = env("DATABASE_URL") val program = config.load[IO].handleErrorWith { case e: ConfigException => IO.println(s"Configuration error: ${e.message}") >> IO.raiseError(e) } ``` -------------------------------- ### Load and Test Configuration Value Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Demonstrates loading a default configuration value and testing its loaded content. Assumes a Cats Effect IO context. ```scala import ciris._ import cats.effect.IO // Mock environment val testValue = ConfigValue.default("test-value") val result = testValue.load[IO] // Result: "test-value" ``` -------------------------------- ### Attempting Environment Variable Parsing Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Demonstrates how to attempt parsing environment variables into specific types like Port and Uri using Ciris. It shows how to handle potential decoding failures and inspect the results. ```scala import ciris._ import ciris.http4s._ env("SERVER_PORT").as[Port].attempt[IO].unsafeRunSync() // Invalid port number: // Left(ConfigError(Port cannot be parsed: "70000" is not a valid port)) env("API_URL").as[Uri].attempt[IO].unsafeRunSync() // Invalid URI: // Left(ConfigError(Uri cannot be parsed: "not a uri")) ``` -------------------------------- ### Create a Fallback Configuration Chain Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Defines a fallback chain for configuration values, trying environment variables first, then system properties, and finally a default value. Useful for providing multiple sources for a single configuration setting. ```scala val value = env("PRIMARY") .or(prop("backup")) .or(default("fallback")) ``` -------------------------------- ### Dynamic ConfigKey Generation Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Shows how to dynamically generate ConfigKeys based on runtime information, such as a service name, for use in configuration loading. ```scala def loadFromService(serviceName: String): ConfigValue[IO, String] = { val key = ConfigKey(s"configuration for service '$serviceName' from registry") ConfigValue.loaded(key, "loaded-value") } ``` -------------------------------- ### Load Configuration with Option Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Loads a configuration value, returning an Option. Use for configuration that may be absent, where None indicates the value is missing. ```scala val result = config.option.load[IO] // Returns None if missing, Some(value) if loaded ``` -------------------------------- ### Using UseOnceSecret for Secure Password Handling Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/use-once-secret.md Demonstrates how to use UseOnceSecret to securely handle a password. The secret is accessed within a `useOnce` block, ensuring it's used immediately and only once. Attempting to reuse it will result in an IllegalStateException. ```scala import cats.effect.IO import ciris.UseOnceSecret val safePattern = UseOnceSecret[IO](password).flatMap { // Use the secret immediately, once useOnce => useOnce.useOnce { chars => verifyPassword(new String(chars)) } // If you need to use it again, something is wrong } ``` -------------------------------- ### Default Port Configuration Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-refined.md Configure server and admin ports using `PosInt` for validation and `.default()` to provide fallback values. This pattern is useful for services that require specific ports but should have sensible defaults if not explicitly configured. ```scala import ciris._ import ciris.refined._ import eu.timepit.refined.types.numeric.PosInt val serverConfig = ( env("SERVER_PORT").as[PosInt].default(8080), env("ADMIN_PORT").as[PosInt].default(9000) ).parMapN { (serverPort, adminPort) => (serverPort, adminPort) }.load[IO] ``` -------------------------------- ### Load Configuration with Exception Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Loads a configuration value. Throws a ConfigException if loading fails. Use when configuration is critical and failure should halt execution. ```scala val result = config.load[IO] // Throws ConfigException if loading fails ``` -------------------------------- ### Load Energy and Power with Squants Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-squants.md Configure energy consumption and output power using Squants' Energy and Power types. Ensure squants.energy._ is imported. ```scala import squants.energy.{Energy, Power} case class EnergyConfig( consumption: Energy, outputPower: Power ) val config = ( env("ENERGY_CONSUMPTION").as[Energy], env("POWER_OUTPUT").as[Power] ).parMapN(EnergyConfig.apply).load[IO] ``` -------------------------------- ### Load Configuration with Ciris Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/quick-example.md This snippet demonstrates loading a complete configuration object from environment variables and system properties. It uses `env`, `prop`, `or`, `as`, `secret`, `default`, `option`, `flatMap`, and `parMapN` to define and load nested configurations. The `load` method is used to trigger the configuration loading process. ```scala import cats.effect.{IO, IOApp} import cats.syntax.all._ import ciris._ import ciris.refined._ import enumeratum.{CirisEnum, Enum, EnumEntry} import eu.timepit.refined.api.Refined import eu.timepit.refined.auto._ import eu.timepit.refined.cats._ import eu.timepit.refined.collection.MinSize import eu.timepit.refined.string.MatchesRegex import eu.timepit.refined.types.net.UserPortNumber import eu.timepit.refined.types.string.NonEmptyString import scala.concurrent.duration._ sealed trait AppEnvironment extends EnumEntry object AppEnvironment extends Enum[AppEnvironment] with CirisEnum[AppEnvironment] { case object Local extends AppEnvironment case object Testing extends AppEnvironment case object Production extends AppEnvironment val values = findValues } import AppEnvironment.{Local, Testing, Production} type ApiKey = String Refined MatchesRegex["[a-zA-Z0-9]{25,40}"] type DatabasePassword = String Refined MinSize[30] final case class ApiConfig( port: Option[UserPortNumber], key: Secret[ApiKey], timeout: Option[FiniteDuration] ) final case class DatabaseConfig( username: NonEmptyString, password: Secret[DatabasePassword] ) final case class Config( name: NonEmptyString, api: ApiConfig, database: DatabaseConfig ) def apiConfig(environment: AppEnvironment): ConfigValue[Effect, ApiConfig] = ( env("API_PORT").or(prop("api.port")).as[UserPortNumber].option, env("API_KEY").as[ApiKey].secret, default(environment match { case Local | Testing => None case Production => Some(10.seconds) }) ).parMapN(ApiConfig) val databaseConfig: ConfigValue[Effect, DatabaseConfig] = ( env("DATABASE_USERNAME").as[NonEmptyString].default("username"), env("DATABASE_PASSWORD").as[DatabasePassword].secret ).parMapN(DatabaseConfig) val config: ConfigValue[Effect, Config] = ( default("my-api").as[NonEmptyString], env("APP_ENV").as[AppEnvironment].flatMap(apiConfig), databaseConfig ).parMapN(Config) object Main extends IOApp.Simple { def run: IO[Unit] = config.load[IO].flatMap(IO.println) } ``` -------------------------------- ### Handle Missing SSM Parameter Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-aws-ssm.md Demonstrates how to handle cases where an SSM parameter does not exist. Loading a missing parameter throws a ConfigException, while using .option returns None. ```scala val parameter = ssm("nonexistent/parameter") parameter.load[IO] // Throws: ConfigException(ConfigError.Missing(...)) parameter.option.load[IO] // Returns: None ``` -------------------------------- ### Sequential Configuration Loading with Dependency Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Loads configuration values sequentially, where the second value depends on the first. Use when one configuration setting influences another. ```scala env("ENV").flatMap { env => if (env == "prod") env("PROD_API_KEY") else env("DEV_API_KEY") } ``` -------------------------------- ### Combinators Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-value.md Explains how to combine ConfigValues using operators like `or`, `alt`, `flatMap`, `map`, `as`, and `base64` for advanced configuration logic. ```APIDOC ## ConfigValue.or(value: => ConfigValue[G, A]): ConfigValue[G, A] ### Description Uses the specified configuration if the value is missing. Only attempts the fallback if the first value is missing (not on other errors). Accumulates errors from both sources. Defaults from the fallback override previous defaults. ### Method `or` ### Parameters - **value** (=> ConfigValue[G, A]) - Required - The fallback configuration value. ### Request Example ```scala val config = env("API_KEY").or(prop("api.key")).or(default("default-key")) ``` ``` ```APIDOC ## ConfigValue.alt(value: => ConfigValue[G, A]): ConfigValue[G, A] ### Description Alternative composition similar to `or`, but also attempts fallback on non-fatal errors. ### Method `alt` ### Parameters - **value** (=> ConfigValue[G, A]) - Required - The alternative configuration value. ### Request Example ```scala val config = env("HOST").alt(env("HOSTNAME")) ``` ``` ```APIDOC ## ConfigValue.flatMap(f: A => ConfigValue[G, B]): ConfigValue[G, B] ### Description Loads a second configuration based on the result of the first. Errors are not accumulated; only the first error is reported. Use `parMapN` or `parTupled` to accumulate errors. ### Method `flatMap` ### Parameters - **f** (A => ConfigValue[G, B]) - Required - A function that takes the successfully loaded value and returns a new `ConfigValue`. ### Request Example ```scala val config = env("ENV").flatMap { env => if (env == "prod") env("PROD_API_KEY") else env("DEV_API_KEY") } ``` ``` ```APIDOC ## ConfigValue.map(f: A => B): ConfigValue[F, B] ### Description Transforms the loaded value. ### Method `map` ### Parameters - **f** (A => B) - Required - A function to transform the loaded value. ### Request Example ```scala val portConfig = env("PORT").as[Int].map(_ + 1000) ``` ``` ```APIDOC ## ConfigValue.as[B](implicit decoder: ConfigDecoder[A, B]): ConfigValue[F, B] ### Description Decodes the value to a different type using a `ConfigDecoder`. ### Method `as` ### Parameters - **decoder** (ConfigDecoder[A, B]) - Required - The decoder to use for type conversion. ### Request Example ```scala val port = env("PORT").as[Int] val timeout = env("TIMEOUT").as[FiniteDuration] ``` ``` ```APIDOC ## ConfigValue.base64(implicit decoderString: ConfigDecoder[A, String], decoderA: ConfigDecoder[String, A]): ConfigValue[F, A] ### Description Base64 decodes the value. Requires decoders for String and back to the original type. ### Method `base64` ### Parameters - **decoderString** (ConfigDecoder[A, String]) - Required - Decoder from the original type to String. - **decoderA** (ConfigDecoder[String, A]) - Required - Decoder from String back to the original type. ### Request Example ```scala val encoded = env("ENCODED_KEY") val decoded = encoded.base64 // Must be able to decode to String and back ``` ``` -------------------------------- ### Create System Property ConfigKey Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Creates a configuration key for a system property. The description will indicate the system property name. ```scala val key = ConfigKey.prop("db.url") // description == "system property db.url" ``` -------------------------------- ### Type Conversion for Configuration Values Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Shows how to convert configuration values loaded from environment variables into specific types like Int, FiniteDuration, and Boolean, with default values provided. ```scala val port = env("PORT").as[Int] val timeout = env("TIMEOUT").as[FiniteDuration] val debug = env("DEBUG").as[Boolean].default(false) ``` -------------------------------- ### Fallback Chain for API Key Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Demonstrates a fallback chain for loading an API key, trying environment variables and properties before settling on a default value. ```scala val apiKey = env("API_KEY") .or(prop("api.key")) .or(env("FALLBACK_API_KEY")) .or(default("development-key")) ``` -------------------------------- ### Attempt Configuration Loading for Error Handling Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Use `attempt` instead of `load` to gain access to `ConfigError` messages. This is beneficial for debugging and providing detailed feedback when configuration loading fails. ```scala apiConfig.attempt[IO] ``` -------------------------------- ### Load JSON Configuration with Circe Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Loads configuration from a JSON string in an environment variable, using Circe for decoding. Requires a Circe decoder for the target configuration type. ```scala val config = env("CONFIG_JSON") .as(circeConfigDecoder[Config]("Config")) .load[IO] ``` -------------------------------- ### Load API Port from Environment or System Property Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Use `env` to read from environment variables and `prop` for system properties. The `or` function provides a fallback mechanism if the primary source is missing. `as[Int]` attempts to convert the value to an integer. ```scala import ciris._ val port: ConfigValue[Effect, Int] = env("API_PORT").or(prop("api.port")).as[Int] ``` -------------------------------- ### User Authentication with Automatic Cleanup Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/use-once-secret.md Authenticate a user by securely handling their password. The `useOnce` method ensures the password character array is nullified immediately after the authentication logic. ```scala import ciris._ import cats.effect.IO def authenticateUser(username: String, password: UseOnceSecret): IO[Boolean] = password.useOnce { pwdChars => IO { val pwd = new String(pwdChars) checkCredentials(username, pwd) // Password array is nullified here } } val auth = env("USERNAME") .flatMap { username => env("PASSWORD") .as[Array[Char]] .useOnceSecret .evalMap { useOnce => authenticateUser(username, useOnce) } } .load[IO] ``` -------------------------------- ### Define Environment-Specific Configurations Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Define distinct configuration case classes for development and production environments. Use `env` to read values and `parMapN` to combine them. ```scala sealed trait Config case class DevConfig(port: Int, admin: Boolean) extends Config case class ProdConfig(port: Int, key: Secret[String]) extends Config val dev = ( env("API_PORT").as[Int], env("ADMIN").as[Boolean] ).parMapN(DevConfig.apply).widen[Config] val prod = ( env("API_PORT").as[Int], env("API_KEY").secret ).parMapN(ProdConfig.apply).widen[Config] ``` -------------------------------- ### Load Values Sequentially using For-Comprehension Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Employ for-comprehensions (or `flatMap`) to load configuration values sequentially. This approach does not accumulate errors; the first error encountered will halt the process. ```scala for { port <- env("API_PORT").or(prop("api.port")).as[Int] timeout <- env("API_TIMEOUT").as[Duration].option } yield ApiConfig(port, timeout) ``` -------------------------------- ### Handle Configuration Errors Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Demonstrates handling configuration errors by chaining operations with flatMap. Use when you need to perform different actions based on whether configuration loaded successfully or failed. ```scala val result = config.attempt[IO].flatMap { case Right(value) => useValue(value) case Left(error) => handleError(error) } ``` -------------------------------- ### Configure Network Address Binding Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Load host and port for network binding from environment variables, with defaults for `BIND_HOST` (localhost) and `BIND_PORT` (8080). ```scala import ciris._ import ciris.http4s._ import com.comcast.ip4s.{Host, Port} import cats.syntax.all._ val bindConfig = ( env("BIND_HOST").as[Host].default(Host.loopback), env("BIND_PORT").as[Port].default(Port(8080)) ).parMapN { (host, port) => (host, port) } ``` -------------------------------- ### Error Reporting with ConfigException Recovery Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-exception.md Demonstrates how to recover from a ConfigException when loading configuration, allowing for logging of the error and using default values. ```scala import ciris._ import cats.effect.IO val config = env("REQUIRED_SETTING") config.load[IO].recover { case _: ConfigException => // Log error and use fallback logger.error("Configuration loading failed, using defaults") defaultValue } ``` -------------------------------- ### Create Default Value with `or` and `default` Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Demonstrates creating a default value using `or` combined with `default`. `a.default(b)` is equivalent to `a.or(default(b))`. ```scala env("API_PORT").as[Int].or(default(9000)) ``` -------------------------------- ### Define Custom Environment Variable Source Source: https://github.com/vlovgr/ciris/blob/main/docs/src/main/mdoc/configurations.md Illustrates how to define a custom configuration source function `env` that reads from environment variables. ```scala def env(name: String): ConfigValue[Effect, String] = ConfigValue.suspend { val key = ConfigKey.env(name) val value = System.getenv(name) if (value != null) { ConfigValue.loaded(key, value) } else { ConfigValue.missing(key) } } ``` -------------------------------- ### ConfigKey Creation within Ciris Loaders Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Illustrates how Ciris's built-in loaders like `env` and `prop` internally create `ConfigKey` instances, and how `ConfigValue.loaded` explicitly uses a `ConfigKey`. ```scala import ciris._ // These internally create ConfigKeys: val envValue = env("PORT") // Creates ConfigKey.env("PORT") val propValue = prop("port.number") // Creates ConfigKey.prop("port.number") val customValue = ConfigValue.loaded( ConfigKey("custom source"), "value" ) ``` -------------------------------- ### prop(name: String): ConfigValue[Effect, String] Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/package-object.md Returns a configuration value loaded from a system property. System properties are queried using System.getProperty(name). ```APIDOC ## prop(name: String): ConfigValue[Effect, String] ### Description Returns a configuration value loaded from a system property. System properties are queried using `System.getProperty(name)`. ### Parameters #### Path Parameters - **name** (String) - Required - The system property name ### Return - **ConfigValue[Effect, String]** - A configuration value for the property ### Request Example ```scala import ciris._ val dbUrl = prop("database.url") val port = prop("server.port").as[Int] ``` ``` -------------------------------- ### Chaining Configuration Sources Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/INDEX.md Chains multiple configuration sources, falling back to the next if the previous is not found. Use to define a hierarchy of configuration providers. ```scala env("PRIMARY") .or(prop("backup")) .or(default("fallback")) ``` -------------------------------- ### ConfigKey Equality with Cats Eq Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Demonstrates using Cats' Eq type class to compare two ConfigKeys for equality based on their descriptions. ```scala import cats.syntax.all._ val key1 = ConfigKey.env("API_KEY") val key2 = ConfigKey.env("API_KEY") key1 === key2 // true val key3 = ConfigKey.env("OTHER_KEY") key1 === key3 // false ``` -------------------------------- ### Create Custom ConfigKey Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Creates a configuration key with a custom description. The description is used in error messages and logging. ```scala val key = ConfigKey("custom configuration source") val desc = key.description // desc == "custom configuration source" ``` -------------------------------- ### Create Environment Variable ConfigKey Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Creates a configuration key for an environment variable. The description will indicate the environment variable name. ```scala val key = ConfigKey.env("API_KEY") // description == "environment variable API_KEY" ``` -------------------------------- ### Pattern Match on ConfigKey Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-key.md Supports pattern matching to extract the description from a ConfigKey, useful for conditional logic based on configuration source. ```scala val key = ConfigKey.env("API_KEY") key match { case ConfigKey(description) => println(s"Loaded from: $description") // Output: Loaded from: environment variable API_KEY } ``` -------------------------------- ### Import ciris and ciris-http4s Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/integration-http4s.md Import necessary ciris and ciris-http4s components for network configuration decoding. ```scala import ciris._ import ciris.http4s._ ``` -------------------------------- ### Sequential Loading with `flatMap` Source: https://github.com/vlovgr/ciris/blob/main/_autodocs/config-value.md Loads a second configuration based on the result of the first. Errors are not accumulated; only the first error encountered is reported. Use `parMapN` or `parTupled` for error accumulation. ```scala val config = env("ENV").flatMap { env => if (env == "prod") env("PROD_API_KEY") else env("DEV_API_KEY") } ```