Skip to content

Instantly share code, notes, and snippets.

@afsalthaj
Created December 5, 2020 00:23
Show Gist options
  • Save afsalthaj/6ab21159a968d489f13c291381b810ec to your computer and use it in GitHub Desktop.
Save afsalthaj/6ab21159a968d489f13c291381b810ec to your computer and use it in GitHub Desktop.
package zio.config.examples
import java.lang.{ Boolean => JBoolean }
import scala.util.{ Failure, Success, Try }
import com.typesafe.config._
import zio.config.typesafe._
import zio.{ IO }
import zio.config._, ConfigDescriptor._
/**
* Load a configuration from different sources based on the given
* configuration schema.
*
* Configuration is obtained in this order:
* 1. from command line arguments (the most visible one)
* 2. from environment variable
* 3. from service `application.conf` (with all the default values)
*
* Examples:
* - args:`--myConfig=111` & env:`MYCONFIG=222` => myConfig=111
* - env:`MYCONFIG=111` & hocon:`myConfig:222` => myConfig=111
* - args:`--myConfig=111` & hocon:`myConfig:222` => myConfig=111
*
* It is possible for environment variables to come with a predefined
* prefix. This feature allows to get a specific namespace for your
* environment variables by using this prefix. See
* [[loadConfiguration]] for more details.
*
* Note: to ensure ensure source/data reconciliation (ie. matching)
* whatever case schema is used, every keys are converted
* lowercase. Eg. `--myConfig` is the same as `--myconfig` or
* `--MYCONFIG`.
*
* @param schema configuration schema
* @tparam A type of the configuration
*/
case class ServiceConfigurationLoader[A <: ServiceParameters](
schema: zio.config.ConfigDescriptor[A]
) {
/**
* Retrieve configuration values.
*
* For environment variables, you may provide you own prefix. Eg. if
* your config key is named `myConfig` and you provide `MY_SERVICE_`
* as prefix, then the descriptor will match with the environment
* variable `MY_SERVICE_MYCONFIG`.
*
* @param prefix prefix used to namespaced you environment variables
* @param args command line arguments
* @return configuration values or an error message
*/
def loadConfiguration(
prefix: String,
args: List[String]
): IO[ReadError[String], A] =
for {
config <- getConfigProgram(prefix, args, schema)
serviceConfig <- IO.fromEither(read(config))
} yield serviceConfig
private def getConfigProgram[A](
prefix: String,
args: List[String],
configSchema: ConfigDescriptor[A]
): IO[ReadError[String], ConfigDescriptor[A]] =
for {
cmdConf <- IO.succeed(
ConfigSource.fromCommandLineArgs(args, Some(ServiceConfigurationLoader.CommandLineKeyDelimiter))
)
sysConf <- ConfigSource.fromSystemEnvLive(
Some(ServiceConfigurationLoader.EnvVarKeyDelimiter),
Some(ServiceConfigurationLoader.EnvVarValueDelimiter)
)
ressConf <- configFromResources
updatedSchema = (configSchema from cmdConf) <>
(configSchema.mapKey(key => addPrefixToKey(prefix)(key).toUpperCase()) from sysConf) <>
(configSchema from ressConf)
} yield updatedSchema
private def configFromResources: IO[ReadError[String], ConfigSource] =
IO.fromEither(TypesafeConfigSource.fromTypesafeConfig(ConfigFactory.defaultApplication()))
}
object ServiceConfigurationLoader {
val CommandLineKeyDelimiter = '.'
val EnvVarKeyDelimiter = '_'
val EnvVarValueDelimiter = ','
}
/**
* Base parameter trait to extends by every services.
*/
trait ServiceParameters {
val serviceName: String
val kafka: KafkaConfig
}
case class KafkaConfig(
bootstrapServers: String,
schemaRegistryUrl: String,
performCleanup: Boolean = false
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment