### Running Jurate Examples via sbt Source: https://github.com/katlasik/jurate/blob/main/README.md Shows the command to run Jurate examples using sbt. It specifies the example class to run and reminds the user to set necessary environment variables beforehand. ```bash sbt "examples/runMain jurate.simpleApp" ``` -------------------------------- ### Install Jurate Library - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Adds Jurate to build.sbt for Scala 3.3+ projects. Requires SBT build tool. Adds the library as a dependency, enabling config derivation features. ```scala libraryDependencies += "io.github.katlasik" %% "jurate" % "0.3.0" ``` -------------------------------- ### Jurate: Annotations for Environment and System Properties with Defaults Source: https://github.com/katlasik/jurate/blob/main/README.md This example illustrates how to use `@prop` and `@env` annotations to specify sources for configuration values. It shows how to provide multiple annotations for a field, where the library tries them in order, and how to define a default value that is used if no annotation provides a value. This allows for flexible configuration sourcing and fallback mechanisms. ```scala case class EmailConfig( @prop("debug.email") @env("EMAIL") @env("ADMIN_EMAIL") email: String = "foo@bar.com" ) // In this example library will first check if system property `debug.email` exists, then it will look for environment variables EMAIL and ADMIN_EMAIL. If none are found default value `foo@bar.com` will be used. ``` -------------------------------- ### Jurate: Nested Case Classes for Configuration Organization Source: https://github.com/katlasik/jurate/blob/main/README.md This example showcases the use of nested case classes to structure configuration hierarchies. Jurate supports loading values into fields of nested case classes, allowing for a more organized and modular configuration definition. This improves readability and maintainability of complex configuration setups. ```scala case class DatabaseConfig( @env("DB_PASSWORD") password: Secret[String], @env("DB_USERNAME") username: String ) case class AppConfig( @env("HOST") host: String, @env("PORT") port: Int = 8080, dbConfig: DatabaseConfig ) ``` -------------------------------- ### Load Basic Configuration - Scala 3 Source: https://context7.com/katlasik/jurate/llms.txt Demonstrates basic configuration loading using @env and @prop annotations on case class fields. The load function reads from environment variables and system properties, returning Either[ConfigError, Config]. Dependencies include the jurate library and proper environment/property setup. Limitations: requires compile-time derivation and proper type annotations. ```scala import jurate.{*, given} case class DbConfig( @env("DB_PASSWORD") password: Secret[String], @env("DB_USERNAME") username: String, @env("DB_PORT") port: Int ) case class Config( @env("HOST") host: String, @env("PORT") port: Int = 8080, @env("ADMIN_EMAIL") adminEmail: Option[String], @prop("app.debug") debug: Boolean, dbConfig: DbConfig ) // Load with actual environment variables and system properties val config: Either[ConfigError, Config] = load[Config] config match { case Right(cfg) => println(s"Server starting on ${cfg.host}:${cfg.port}") println(s"DB: ${cfg.dbConfig.username}@localhost:${cfg.dbConfig.port}") case Left(error) => println(s"Configuration error: ${error.getMessage}") } ``` -------------------------------- ### Integrate Configuration with Cats Effect IO in Scala Source: https://context7.com/katlasik/jurate/llms.txt This Scala snippet shows integration of configuration loading with Cats Effect IO for functional programming. It defines an AppConfig case class with default values, uses IOApp.Simple to create an application that loads config and starts a server. Dependencies include Cats Effect for IO handling and Jurate for config. Input is environment variables; output is server startup messages. Limitations include needing proper environment variables set for successful loading. ```scala import cats.effect.{IO, IOApp} import jurate.{*, given} case class AppConfig( @env("APP_NAME") name: String = "MyApp", @env("APP_VERSION") version: String, @env("PORT") port: Int = 8080 ) object MyApplication extends IOApp.Simple { def run: IO[Unit] = for { config <- IO.fromEither(load[AppConfig]) _ <- IO.println(s"Starting ${config.name} v${config.version}") _ <- IO.println(s"Listening on port ${config.port}") _ <- startServer(config) } yield () def startServer(config: AppConfig): IO[Unit] = IO.println(s"Server running on :${config.port}") } // With environment: APP_VERSION=1.2.3 // Output: // Starting MyApp v1.2.3 // Listening on port 8080 ``` -------------------------------- ### Configure Tapir HTTP Server with Environment Settings in Scala Source: https://context7.com/katlasik/jurate/llms.txt This Scala snippet configures a web server using Tapir and Jurate for environment-based settings. It defines an HttpConfig case class, loads config, sets up a hello endpoint, and starts a Netty server. Dependencies include Tapir for HTTP endpoints, Ox for supervision, and Jurate for config. Input is environment variables for host and port; output is server startup and interaction messages. Limitations include manual server stopping via user input. ```scala import sttp.tapir.* import sttp.tapir.server.netty.sync.NettySyncServer import jurate.{*, given} import ox.* import ox.either.* case class HttpConfig( @env("HTTP_HOST") host: String = "localhost", @env("HTTP_PORT") port: Int = 8080 ) @main def runServer(): Unit = supervised { val config: HttpConfig = load[HttpConfig].orThrow val helloEndpoint = endpoint.get .in("hello") .in(query[String]("name")) .out(stringBody) .handleSuccess(name => s"Hello, $name!") println(s"Starting server on ${config.host}:${config.port}") val handle = NettySyncServer() .port(config.port) .host(config.host) .addEndpoint(helloEndpoint) .start() println("Press ENTER to stop the server") scala.io.StdIn.readLine() println("Stopping server...") handle.stop() println("Server stopped.") } ``` -------------------------------- ### Default Error Handling in Jurate (Scala) Source: https://github.com/katlasik/jurate/blob/main/README.template.md Handle configuration loading errors using pattern matching on Either[ConfigError, Config], printing a default message listing issues like missing variables. This provides a simple text-based error summary without additional setup. Limitations include basic formatting unsuitable for complex displays. ```Scala case class AppConfig( @env("PORT") port: Int, @env("HOST") host: String ) load[AppConfig] match { case Left(error) => println(error.getMessage) case Right(config) => // ... } ``` -------------------------------- ### Custom Error Printer implementation in Scala Source: https://github.com/katlasik/jurate/blob/main/README.md Provides an example of creating a custom error printer by implementing the `ErrorPrinter` trait. The `CompactPrinter` formats errors into a concise string, concatenating messages for missing or invalid fields. ```scala import jurate.ErrorPrinter object CompactPrinter extends ErrorPrinter { def format(error: ConfigError): String = error.reasons.map { case Missing(field, _) => s"Missing: $field" case Invalid(_, detail, _, _) => s"Invalid: $detail" case Other(field, detail, _) => s"Error: $detail" }.mkString(" | ") } error.print(using CompactPrinter) // Missing: port | Missing: host ``` -------------------------------- ### Define and Load Scala 3 Configuration with Jurate Source: https://github.com/katlasik/jurate/blob/main/README.md This snippet shows how to define case classes for configuration, using `@env` and `@prop` annotations to map fields to environment variables and system properties. It demonstrates loading the configuration using the `load` method. Dependencies include the jurate library. Inputs are environment variables and system properties, and the output is a `Config` object wrapped in `Either`. ```scala import jurate.{*, given} case class DbConfig( @env("DB_PASSWORD") password: Secret[String], @env("DB_USERNAME") username: String ) case class Config( @env("HOST") host: String, @env("PORT") port: Int = 8080, @env("ADMIN_EMAIL") adminEmail: Option[String], @prop("app.debug") debug: Boolean = false, dbConfig: DbConfig ) println(load[Config]) // Right(Config(localhost,8080,None,false,DbConfig(Secret(d74ff0ee8d),db_reader))) ``` -------------------------------- ### Mocked ConfigReader for Testing (Scala) Source: https://github.com/katlasik/jurate/blob/main/README.template.md Create a mocked ConfigReader to simulate environment variables and properties for testing configuration loading without real system dependencies. It uses onEnv and onProp to set values, then loads the case class via the load function. This is ideal for unit tests, returning the configured object directly. ```Scala case class DbConf(@env("DATABASE_HOST") host: String, @prop("dbpass") password: String) given ConfigReader = ConfigReader .mocked .onEnv("DATABASE_HOST", "localhost") .onProp("dbpass", "mypass") println(load[DbConf]) ``` -------------------------------- ### Use Annotation Fallbacks - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Demonstrates using multiple annotations with fallbacks in order of precedence. Requires Scala 3 and Jurate. Loads value from first existing source or uses default. ```scala case class EmailConfig( @prop("debug.email") @env("EMAIL") @env("ADMIN_EMAIL") email: String = "foo@bar.com" ) ``` -------------------------------- ### Mock ConfigReader for Testing in Scala Source: https://github.com/katlasik/jurate/blob/main/README.md Shows how to use a mocked `ConfigReader` for testing purposes. It allows overriding environment variables and system properties using `onEnv` and `onProp` methods, providing specific values for testing configuration loading of a `DbConf` case class. ```scala case class DbConf(@env("DATABASE_HOST") host: String, @prop("dbpass") password: String) given ConfigReader = ConfigReader .mocked .onEnv("DATABASE_HOST", "localhost") .onProp("dbpass", "mypass") println(load[DbConf]) // Right(DbConf(localhost,mypass)) ``` -------------------------------- ### Jurate: Import Givens for Configuration Loading Source: https://github.com/katlasik/jurate/blob/main/README.md To enable Jurate's configuration loading capabilities, you need to import the necessary givens. This import provides the `ConfigReader` instances required to read values from the environment or system properties. This is a prerequisite for using the `load` method. ```scala import jurate.{*, given} ``` -------------------------------- ### Handle Configuration Errors in Scala Source: https://context7.com/katlasik/jurate/llms.txt This Scala snippet demonstrates error handling for configuration loading using the Jurate library. It defines a Config case class with environment and property annotations, uses a mocked ConfigReader to simulate invalid or missing values, and handles the result by printing detailed error messages for all issues. Dependencies include the Jurate library for configuration management. Input is environment variables and system properties; output is error messages or successful config load. Limitations include reliance on mocked reader for testing. ```scala import jurate.{*, given} case class Config( @env("PORT") port: Int, @env("HOST") @prop("sys.host") host: String, @env("SECRET") secret: Secret[String], @env("TIMEOUT") timeout: Int ) given ConfigReader = ConfigReader.mocked .onEnv("PORT", "not_a_number") // Invalid value // HOST and sys.host missing // SECRET missing // TIMEOUT missing val result = load[Config] result match { case Left(error) => println(error.getMessage) // Configuration loading failed with following issues: // Loaded invalid value: can't decode integer, received value: 'not_a_number' // Missing environment variable HOST, missing system property sys.host // Missing environment variable SECRET // Missing environment variable TIMEOUT case Right(_) => println("Config loaded") } ``` -------------------------------- ### Test with mocked configuration reader in Scala Source: https://context7.com/katlasik/jurate/llms.txt Demonstrates how to override environment and system properties for testing purposes. Shows both production and test usage patterns with assertions. ```scala import jurate.{*, given} case class DbConfig( @env("DATABASE_HOST") host: String, @prop("db.password") password: String, @env("DB_PORT") port: Int = 5432 ) // Production usage - reads from actual environment def loadProductionConfig(): Either[ConfigError, DbConfig] = { load[DbConfig] // Uses implicit LiveConfigReader } // Test usage - controlled values def testDatabaseConnection(): Unit = { given ConfigReader = ConfigReader .mocked .onEnv("DATABASE_HOST", "localhost") .onProp("db.password", "test_password") .onEnv("DB_PORT", "5433") val config = load[DbConfig] // Right(DbConfig("localhost", "test_password", 5433)) config match { case Right(cfg) => assert(cfg.host == "localhost") assert(cfg.port == 5433) println("Test config loaded successfully") case Left(error) => fail(s"Config load failed: $error") } } ``` -------------------------------- ### Default Error Handling with getMessage in Scala Source: https://github.com/katlasik/jurate/blob/main/README.md Illustrates the default error handling mechanism for configuration loading, which returns an `Either[ConfigError, Config]`. When an error occurs, `error.getMessage` provides a text-based list of issues, such as missing environment variables. ```scala case class AppConfig( @env("PORT") port: Int, @env("HOST") host: String ) load[AppConfig] match { case Left(error) => println(error.getMessage) // Configuration loading failed with following issues: // Missing environment variable PORT // Missing environment variable HOST case Right(config) => // ... } ``` -------------------------------- ### Load Sealed Trait Subclasses - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Loads the first successfully loading subclass for a sealed trait. Requires Scala 3 and Jurate. Useful for variant configurations. ```scala sealed trait MessagingConfig case class LiveConfig(@env("BROKER_ADDRESS") brokerAddress: String) extends MessagingConfig case class TestConfig(@prop("BROKER_NAME" ) brokerName: String) extends MessagingConfig case class Config(messaging: MessagingConfig) ``` -------------------------------- ### Handle Optional Values - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Shows loading optional fields using Option type. Requires Scala 3 and Jurate. Sets field to None if no value found for the annotation. ```scala case class AdminEmailConfig( @env("ADMIN_EMAIL") adminEmail: Option[String] ) ``` -------------------------------- ### Load Nested Configuration - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Loads a nested case class configuration from environment variables using @env annotations. Requires Scala 3 and Jurate library. Outputs a Config instance or errors if loading fails. ```scala import jurate.{*, given} case class DbConfig( @env("DB_PASSWORD") password: Secret[String], @env("DB_USERNAME") username: String ) case class Config( @env("HOST") host: String, @env("PORT") port: Int = 8080, @env("ADMIN_EMAIL") adminEmail: Option[String], @prop("app.debug") debug: Boolean = false, dbConfig: DbConfig ) println(load[Config]) ``` -------------------------------- ### Table Format Error Display using TablePrinter in Scala Source: https://github.com/katlasik/jurate/blob/main/README.md Demonstrates using `TablePrinter` to display configuration loading errors in a formatted table for improved readability. The output includes columns for 'Field', 'Source', and 'Message' for each configuration issue. ```scala import jurate.printers.TablePrinter load[Config] match { case Left(error) => System.err.println(error.print(using TablePrinter)) // ┌───────┬────────────┬─────────────────────────────┐ // │ Field │ Source │ Message │ // ├───────┼────────────┼─────────────────────────────┤ // │ port │ PORT (env) │ Missing configuration value │ // ├───────┼────────────┼─────────────────────────────┤ // │ host │ HOST (env) │ Missing configuration value │ // └───────┴────────────┴─────────────────────────────┘ case Right(config) => // ... } ``` -------------------------------- ### Loading Collections in Jurate (Scala) Source: https://github.com/katlasik/jurate/blob/main/README.template.md This snippet demonstrates loading a comma-separated list of integers from an environment variable into a List[Int] using Jurate's @env annotation. It requires the Jurate library and an environment variable set with comma-separated values. The output is an Either containing the parsed case class or an error. ```Scala case class Numbers(@env("NUMBERS") numbers: List[Int]) println(load[Numbers]) ``` -------------------------------- ### Handle Optional Configuration - Scala 3 Source: https://context7.com/katlasik/jurate/llms.txt Demonstrates handling optional configuration values using Option types with @env annotations. Optional values gracefully handle missing environment variables without throwing errors. Dependencies include ConfigReader with mocked environment values. Limitation: Option types require explicit handling for default values or may result in None. ```scala import jurate.{*, given} case class FeatureFlags( @env("ENABLE_BETA") betaFeatures: Option[Boolean], @env("MAX_UPLOAD_SIZE") maxUploadMb: Option[Int], @env("API_KEY") apiKey: Option[String] ) given ConfigReader = ConfigReader.mocked .onEnv("ENABLE_BETA", "true") val flags = load[FeatureFlags] // Right(FeatureFlags(Some(true), None, None)) flags.map { f => f.betaFeatures.foreach(enabled => println(s"Beta: $enabled")) f.maxUploadMb.getOrElse(10) // Use 10 MB default if not set } ``` -------------------------------- ### Jurate: Loading Subclasses of Sealed Traits Source: https://github.com/katlasik/jurate/blob/main/README.md Jurate supports loading configuration into subclasses of sealed traits. The library attempts to load each subclass in order, and the first one that successfully loads its required fields is chosen. This allows for polymorphic configuration based on different subtypes. ```scala sealed trait MessagingConfig case class LiveConfig(@env("BROKER_ADDRESS") brokerAddress: String) extends MessagingConfig case class TestConfig(@prop("BROKER_NAME" ) brokerName: String) extends MessagingConfig case class Config(messaging: MessagingConfig) // The same works for enums with fields enum MessagingConfig: case LiveConfig(@env("BROKER_ADDRESS") brokerAddress: String) case TestConfig(@prop("BROKER_NAME" ) brokerName: String) case class Config(messaging: MessagingConfig) ``` -------------------------------- ### Configure Fallback Chain - Scala 3 Source: https://context7.com/katlasik/jurate/llms.txt Shows how to configure multiple configuration sources with automatic fallback using @prop and @env annotations in order. The library tries each source sequentially and falls back to default values if none are found. Dependencies include ConfigReader with mocked values for testing. Limitation: order of annotation definition determines fallback priority. ```scala import jurate.{*, given} case class ServiceConfig( // Tries system property "debug.email", then ENV vars EMAIL, ADMIN_EMAIL // Falls back to "admin@example.com" if none are found @prop("debug.email") @env("EMAIL") @env("ADMIN_EMAIL") email: String = "admin@example.com", @env("SERVICE_PORT") @prop("service.port") port: Int = 3000 ) given ConfigReader = ConfigReader.mocked .onProp("service.port", "8080") val result = load[ServiceConfig] // Right(ServiceConfig("admin@example.com", 8080)) ``` -------------------------------- ### Jurate: Optional Configuration Fields using Option Type Source: https://github.com/katlasik/jurate/blob/main/README.md This snippet demonstrates how to define optional configuration fields using Scala's `Option` type. If the corresponding environment variable or system property is not found, the field will be automatically set to `None`, preventing application crashes due to missing configuration. This enhances robustness by gracefully handling absent settings. ```scala case class AdminEmailConfig( @env("ADMIN_EMAIL") adminEmail: Option[String], ) ``` -------------------------------- ### Jurate: Loading Singleton Enum Values from Configuration Source: https://github.com/katlasik/jurate/blob/main/README.md This code illustrates how Jurate can load values for singleton enums (enums without fields) directly from environment variables or system properties. The library performs a case-sensitive lookup to match the provided string value with an enum case. Custom decoders can be provided for more complex enum loading logic. ```scala enum Environment: case DEV, PROD, STAGING case class EnvConfig( @env("ENV") env: Environment ) // If you want to customize loading of enum you can provide your own instance of `ConfigDecoder`: given ConfigDecoder[Environment] = new ConfigDecoder[Environment]: def decode(raw: String, ctx: DecodingContext): Either[ConfigError, Environment] = val rawLowercased = raw.trim().toLowerCase() Environment.values .find(_.toString().toLowerCase() == rawLowercased) .toRight(ConfigError.invalid(ctx.fieldPath, s"Couldn't find right value for Environment", raw, ctx.evaluatedAnnotation)) ``` -------------------------------- ### Load Enums with Fields - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Loads enums with fields, selecting the first matching case. Requires Scala 3 and Jurate. Fields are loaded from annotations within enum cases. ```scala enum MessagingConfig: case LiveConfig(@env("BROKER_ADDRESS") brokerAddress: String) case TestConfig(@prop("BROKER_NAME" ) brokerName: String) case class Config(messaging: MessagingConfig) ``` -------------------------------- ### Table Format Error Printing (Scala) Source: https://github.com/katlasik/jurate/blob/main/README.template.md Use TablePrinter to format ConfigError details in a tabular structure for better readability, showing field, source, and message. Import jurate.printers.TablePrinter and apply it via error.print(using TablePrinter). This enhances error diagnostics in console output for debugging. ```Scala import jurate.printers.TablePrinter load[Config] match { case Left(error) => System.err.println(error.print(using TablePrinter)) case Right(config) => // ... } ``` -------------------------------- ### Load Enum Values - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Loads singleton enum values from environment variables with case-sensitive matching. Requires Scala 3 and Jurate. Fails if no matching enum case found. ```scala enum Environment: case DEV, PROD, STAGING case class EnvConfig( @env("ENV") env: Environment ) ``` -------------------------------- ### Custom Error Printer Implementation (Scala) Source: https://github.com/katlasik/jurate/blob/main/README.template.md Extend ErrorPrinter trait to create a compact string formatter for ConfigError, mapping reasons to custom messages like 'Missing' or 'Invalid'. Apply it using error.print(using CompactPrinter) for tailored output. This allows flexible error presentation, such as joining issues with separators. ```Scala import jurate.ErrorPrinter object CompactPrinter extends ErrorPrinter { def format(error: ConfigError): String = error.reasons.map { case Missing(field, _) => s"Missing: $field" case Invalid(_, detail, _, _) => s"Invalid: $detail" case Other(field, detail, _) => s"Error: $detail" }.mkString(" | ") } error.print(using CompactPrinter) ``` -------------------------------- ### Load sealed trait implementations in Scala Source: https://context7.com/katlasik/jurate/llms.txt Shows how to load sealed trait implementations trying subclasses in order. The first successfully loading subclass wins based on the provided environment variables. ```scala import jurate.{*, given} sealed trait DatabaseConfig case class PostgresConfig( @env("PG_HOST") host: String, @env("PG_PORT") port: Int ) extends DatabaseConfig case class MySqlConfig( @env("MYSQL_HOST") host: String, @env("MYSQL_PORT") port: Int ) extends DatabaseConfig case class Config(database: DatabaseConfig) // First successfully loading subclass wins given ConfigReader = ConfigReader.mocked .onEnv("MYSQL_HOST", "mysql.internal") .onEnv("MYSQL_PORT", "3306") val config = load[Config] // Right(Config(MySqlConfig("mysql.internal", 3306))) ``` -------------------------------- ### Implement Custom ConfigDecoder in Scala Source: https://github.com/katlasik/jurate/blob/main/README.md Demonstrates how to create a custom decoder for a user-defined class `MyClass` by implementing the `ConfigDecoder` typeclass. It handles potential errors, such as empty input strings, and returns a `Right` with the decoded object on success. ```scala class MyClass(val value: String) given ConfigDecoder[MyClass] with { def decode(raw: String, ctx: DecodingContext): Either[ConfigError, MyClass] = { if (raw.isEmpty) Left(ConfigError.invalid(ctx.fieldPath, "Value is empty", raw, ctx.evaluatedAnnotation)) else Right(new MyClass(raw)) } } ``` -------------------------------- ### Use Secret Values - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Loads secret values wrapped in Secret type for secure logging. Requires Scala 3 and Jurate. Displays SHA-256 hash instead of raw value in outputs. ```scala case class DbCredsConfig( @env("DB_PASSWORD") password: Secret[String], @env("DB_USERNAME") username: String ) println(load[DbCredsConfig]) ``` -------------------------------- ### Jurate: Loading Comma-Separated Values into Collections Source: https://github.com/katlasik/jurate/blob/main/README.md Jurate allows loading comma-separated string values from environment variables directly into collection types like `List`. The library automatically parses the string and converts each element to the target type of the collection. Currently, the separator cannot be customized. ```scala case class Numbers(@env("NUMBERS") numbers: List[Int]) println(load[Numbers]) // Right(Numbers(List(1, 2, 3))) // With environment variable containing "1,2,3" the `result` will contain `Right(Numbers(List(1,2,3)))`. ``` -------------------------------- ### Load complex enum cases with fields in Scala Source: https://context7.com/katlasik/jurate/llms.txt Demonstrates loading enum cases with their own configuration fields using environment variables and properties. The first available enum case loads successfully based on provided values. ```scala import jurate.{*, given} enum MessagingConfig: case LiveConfig(@env("BROKER_ADDRESS") brokerAddress: String) case TestConfig(@env("BROKER_NAME") brokerName: String) case LocalConfig(@prop("local.port") port: Int) case class AppConfig(messaging: MessagingConfig) // First available enum case loads successfully given ConfigReader = ConfigReader.mocked .onEnv("BROKER_NAME", "test-broker") val config = load[AppConfig] // Right(AppConfig(TestConfig("test-broker"))) // With live config given reader2: ConfigReader = ConfigReader.mocked .onEnv("BROKER_ADDRESS", "kafka.prod.com:9092") val liveConfig = load[AppConfig](using reader2) // Right(AppConfig(LiveConfig("kafka.prod.com:9092"))) ``` -------------------------------- ### Jurate: Handling Sensitive Data with Secret Type Source: https://github.com/katlasik/jurate/blob/main/README.md The `Secret` type in Jurate provides a way to handle sensitive configuration values like passwords or API keys. When a `Secret` field is printed or logged, it displays a short SHA-256 hash of the actual value instead of the plaintext. This helps prevent accidental exposure of sensitive information while still allowing for debugging. ```scala case class DbCredsConfig( @env("DB_PASSWORD") password: Secret[String], @env("DB_USERNAME") username: String ) println(load[DbCredsConfig]) // Right(DbCredsConfig(Secret(d74ff0ee8d),db_reader)) // The `Secret` type shows only the first 10 characters of the SHA-256 hash, which helps with debugging while keeping sensitive data protected. ``` -------------------------------- ### Custom Enum Decoder - Scala Source: https://github.com/katlasik/jurate/blob/main/README.template.md Provides custom ConfigDecoder for enums with case-insensitive matching. Requires Scala 3 and Jurate. Allows flexible enum value parsing from strings. ```scala given ConfigDecoder[Environment] = new ConfigDecoder[Environment]: def decode(raw: String, ctx: DecodingContext): Either[ConfigError, Environment] = val rawLowercased = raw.trim().toLowerCase() Environment.values .find(_.toString().toLowerCase() == rawLowercased) .toRight(ConfigError.invalid(ctx.fieldPath, s"Couldn't find right value for Environment", raw, ctx.evaluatedAnnotation)) ``` -------------------------------- ### Load Enumerations from Configuration - Scala 3 Source: https://context7.com/katlasik/jurate/llms.txt Demonstrates loading enum values from environment variables with case-sensitive matching using simple enum definitions. Dependencies include jurate library with built-in enum decoders. Limitation: Default decoder is case-sensitive, requiring exact match of enum value names. ```scala import jurate.{*, given} enum Environment: case DEV, PROD, STAGING enum LogLevel: case DEBUG, INFO, WARN, ERROR case class AppConfig( @env("ENV") environment: Environment, @env("LOG_LEVEL") logLevel: LogLevel = LogLevel.INFO ) given ConfigReader = ConfigReader.mocked .onEnv("ENV", "PROD") .onEnv("LOG_LEVEL", "WARN") val config = load[AppConfig] // Right(AppConfig(PROD, WARN)) config.map { c => if c.environment == Environment.PROD then println("Running in production mode") } ``` -------------------------------- ### Implement custom type decoders in Scala Source: https://context7.com/katlasik/jurate/llms.txt Shows how to create custom decoders for domain types (EmailAddress and URL) with validation logic. Includes error handling for invalid inputs. ```scala import jurate.{*, given} import java.net.URL case class EmailAddress(value: String) { require(value.contains("@"), "Invalid email") } given ConfigDecoder[EmailAddress] with { def decode(value: String): Either[ConfigError, EmailAddress] = { if value.isEmpty then Left(ConfigError.invalid("Email cannot be empty", value)) else if !value.contains("@") then Left(ConfigError.invalid("Email must contain @", value)) else Right(EmailAddress(value)) } } given ConfigDecoder[URL] with { def decode(value: String): Either[ConfigError, URL] = { try Right(new URL(value)) catch case e: Exception => Left(ConfigError.invalid(s"Invalid URL: ${e.getMessage}", value)) } } case class NotificationConfig( @env("ADMIN_EMAIL") adminEmail: EmailAddress, @env("WEBHOOK_URL") webhookUrl: URL ) given ConfigReader = ConfigReader.mocked .onEnv("ADMIN_EMAIL", "admin@example.com") .onEnv("WEBHOOK_URL", "https://hooks.example.com/notify") val config = load[NotificationConfig] // Right(NotificationConfig(EmailAddress("admin@example.com"), URL("https://..."))) ``` -------------------------------- ### Load comma-separated values into collections in Scala Source: https://context7.com/katlasik/jurate/llms.txt Illustrates loading comma-separated environment variables into various collection types (List and Seq) with different element types (String, Int, Long). ```scala import jurate.{*, given} case class ServiceConfig( @env("ALLOWED_HOSTS") allowedHosts: List[String], @env("PORTS") ports: List[Int], @env("TIMEOUTS_MS") timeouts: Seq[Long] ) given ConfigReader = ConfigReader.mocked .onEnv("ALLOWED_HOSTS", "localhost, api.example.com, cdn.example.com") .onEnv("PORTS", "8080, 8081, 8082") .onEnv("TIMEOUTS_MS", "1000, 5000, 30000") val config = load[ServiceConfig] // Right(ServiceConfig( // List("localhost", "api.example.com", "cdn.example.com"), // List(8080, 8081, 8082), // List(1000, 5000, 30000) // )) config.map { c => c.ports.foreach(p => println(s"Binding to port $p")) } ``` -------------------------------- ### Manage Secret Configuration Values - Scala 3 Source: https://context7.com/katlasik/jurate/llms.txt Shows how to protect sensitive configuration values using Secret type, which automatically masks content in logs and error messages while preserving actual values for use. Dependencies include jurate library with Secret type support. Limitation: Secret values still require proper access to the underlying value property when needed. ```scala import jurate.{*, given} case class Credentials( @env("API_KEY") apiKey: Secret[String], @env("DB_PASSWORD") dbPassword: Secret[String], @env("USERNAME") username: String ) given ConfigReader = ConfigReader.mocked .onEnv("API_KEY", "sk_live_abc123xyz") .onEnv("DB_PASSWORD", "super_secret_pass") .onEnv("USERNAME", "admin") val creds = load[Credentials] println(creds) // Right(Credentials(*****, *****, admin)) // Actual values still accessible creds.map { c => val key: String = c.apiKey.value println(s"Using key: ${key}") // Full value available when needed } ``` -------------------------------- ### Custom Enum Decoder Implementation - Scala 3 Source: https://context7.com/katlasik/jurate/llms.txt Shows how to create custom enum decoders for case-insensitive matching and custom error messages by implementing ConfigDecoder. Dependencies include ConfigDecoder trait and custom implementation logic. Limitation: Custom decoder logic must handle all parsing edge cases and provide meaningful error messages. ```scala import jurate.{*, given} enum Protocol: case HTTP, HTTPS given ConfigDecoder[Protocol] = new ConfigDecoder[Protocol]: def decode(raw: String): Either[ConfigError, Protocol] = val normalized = raw.trim().toLowerCase() Protocol.values .find(_.toString().toLowerCase() == normalized) .toRight(ConfigError.invalid( s"Invalid protocol (expected: http, https)", raw )) case class ServerConfig(@env("PROTOCOL") protocol: Protocol) given ConfigReader = ConfigReader.mocked .onEnv("PROTOCOL", "hTtPs") // Mixed case val config = load[ServerConfig] // Right(ServerConfig(HTTPS)) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.