sealed trait ConfigDescriptor[A] extends AnyRef
- Self Type
- ConfigDescriptor[A]
- Alphabetic
- By Inheritance
- ConfigDescriptor
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
final
def
<*>[B](that: ⇒ ConfigDescriptor[B]): ConfigDescriptor[(A, B)]
<*>is an alias to functionzip -
final
def
<+>[B](that: ⇒ ConfigDescriptor[B]): ConfigDescriptor[Either[A, B]]
<+>is an alias to functionorElseEither.<+>is an alias to functionorElseEither. This is used to represent fall-back logic when we describe config retrievals. UnlikeorElse, the the fall-back config parameter can have a different type inorElseEither.Example:
val config: ConfigDescriptor[Either[Int, String]] = int("MONTH") <+> string("MONTH")
This is a description that represents the following: Try to retrieve the value of a MONTH as an
Int, and if there is a format error, try and retrieve it as aString.Detail:
We know
ConfigDescriptoris a program that describes the retrieval of a set of configuration parameters. In the below example, we can either depend on a configuration calledpasswordor atokenboth being of the same type, in this case, a String.Example:
Given:
final case class BasicAuth(username: String, password: String) final case class OAuth(clientId: String, secret: String) val basicAuth: ConfigDescriptor[BasicAuth] = (string("USERNAME") zip string("PASSWORD")).to[BasicAuth] val oAuth: ConfigDescriptor[OAuth] = (string("CLIENT_ID") zip string("SECRET")).to[OAuth] val myConfig: ConfigDescriptor[Either[BasicAuth, OAuth]] = basicAuth <+> oAuth
then,
val source = ConfigSource.fromMap(Map("USERNAME" -> "abc", "PASSWORD" -> "cde") read(myConfig from source)
returns:
Left(BasicAuth("abc", "def")
Similarly,
val source = ConfigSource.fromMap(Map("CLIENT_ID" -> "xyz", "SECRET" -> "afg==") read(myConfig from source)
returns:
Right(OAuth("xyz", "afg==")
-
final
def
<>(that: ⇒ ConfigDescriptor[A]): ConfigDescriptor[A]
<>is an alias to functionorElse.<>is an alias to functionorElse. This is used to represent fall-back logic when we describe config retrievals.Example:
val config: ConfigDescriptor[String] = string("token") <> string("password")
This is a description that represents the following: Try to retrieve the value of a parameter called "token", or else try to retrieve the value of parameter called "password"
We know
ConfigDescriptoris a program that describes the retrieval of a set of configuration parameters.In the below example, we can either depend on a configuration called
passwordor atokenboth being of the same type, in this case, a String.Example:
final case class Config(tokenOrPassword: String, port: Int) object Config { val databaseConfig: ConfigDescriptor[Config] = (string("token") <> string("password") zip int("PORT")).to[Config] }
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
??(description: String): ConfigDescriptor[A]
??is an alias todescribewhich allows us to inject additional documentation to the configuration parameters.??is an alias todescribewhich allows us to inject additional documentation to the configuration parameters.Example:
val port = int("PORT") ?? "database port"
A more detailed example:
Here is a program that describes (or a ConfigDescriptor that represents) reading a
USERNAMEwhich is a String andPORTwhich is an Int, and load it to a case classConfigfinal case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT")).to[Config] }
Later on you decided to annotate each one of them with extra documentation, which is later seen in error messages if config retrieval is a failure, and it's also used while documenting your configuration using
ConfigDocsModuleval dbConfigWithDoc: ConfigDescriptor[Config] = (string("USERNAME") ?? "db username" zip int("PORT") ?? "db port" ).to[Config]
If you try and read this config from an empty source, it emits an error message with the details you provided.
import zio.config._, ConfigDescriptor._ read(Config.databaseConfig from ConfigSource.fromMap(Map.empty))
returns:
╥ ╠══╦══╗ ║ ║ ║ ║ ║ ╠─MissingValue ║ ║ ║ path: PORT ║ ║ ║ Details: db port, value of type int ║ ║ ▼ ║ ║ ║ ╠─MissingValue ║ ║ path: USERNAME ║ ║ Details: db username, value of type string ║ ▼ ▼
Or, you can also use a common documentation for an entire set of config parameters.
val detailedConfigDescriptor: ConfigDescriptor[Config] = configDescriptor ?? "Configuration related to database"
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
-
final
def
default(value: A): ConfigDescriptor[A]
defaultfunction allows us to inject default values to existing configdefaultfunction allows us to inject default values to existing configExample:
val port = int("PORT").default(8080)
A more detailed example:
Here is a program that describes (or a ConfigDescriptor that represents) reading a
USERNAMEwhich is a String andPORTwhich is an Int, and load it to a case classConfigfinal case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT").default(8080)).to[Config] }
In the above case, if username is missing, then it prints out an error, however if PORT is missing, it falls back to 8080.
In fact you can give a default to an entire config
For example:
final case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT")).to[Config].default(Config("jon", 8080)) }
Sometimes this can be used along with automatic derivation supported through zio-config-magnolia.
import zio.config.magnolia._, zio.config._, ConfigDescriptor._ final case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = descriptor[Config].default(Config("jon", 8080)) } // This is a typical example where we mix auto derivation with manual definitions.
-
final
def
describe(description: String): ConfigDescriptor[A]
describefunction allows us to inject additional documentation to the configuration parameters.describefunction allows us to inject additional documentation to the configuration parameters.Example:
val port = int("PORT") ?? "database port"
A more detailed example:
Here is a program that describes (or a ConfigDescriptor that represents) reading a
USERNAMEwhich is a String and aPORTwhich is an Int, and load it to a case classConfigfinal case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT")).to[Config] }
Later on you decided to annotate each one of them with extra documentation, which is later seen in error messages if config retrieval is a failure, and it's also used while documenting your configuration using
ConfigDocsModuleval dbConfigWithDoc: ConfigDescriptor[Config] = (string("USERNAME") ?? "db username" zip int("PORT") ?? "db port").to[Config]
If you try and read this config from an empty source, it emits an error message with the details you provided.
import zio.config._, ConfigDescriptor._ read(Config.databaseConfig from ConfigSource.fromMap(Map.empty))
returns:
╥ ╠══╦══╗ ║ ║ ║ ║ ║ ╠─MissingValue ║ ║ ║ path: PORT ║ ║ ║ Details: db port, value of type int ║ ║ ▼ ║ ║ ║ ╠─MissingValue ║ ║ path: USERNAME ║ ║ Details: db username, value of type string ║ ▼ ▼
Or, you can also use a common documentation for an entire set of config parameters.
val detailedConfigDescriptor: ConfigDescriptor[Config] = configDescriptor ?? "Configuration related to database"
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
finalize(): Unit
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
-
final
def
from(that: ConfigDescriptorModule.ConfigSource): ConfigDescriptor[A]
Attach a source to the
ConfigDescriptor.Attach a source to the
ConfigDescriptor.Example:
val config = string("PORT") from ConfigSource.fromMap(Map.empty)
configis a description that says there is a key calledPORTin constant map source. You can use the description to read the configval either: ZIO[Any, ReadError[String], String] = read(config)
You can also tag a source per config field, or one global source to an entire config.
final case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT")).to[Config] }
In the above example,
dbConfigis not associated with any source. By default the source will be empty.To attach a config (especially during a read operation) is as easy as:
read(dbConfig from ConfigSource.fromMap(Map("USERNAME" -> "afs", "PORT" -> "8080")) // Right(Config("afs", 8080))
Obviously, source can be attached independently.
val configSource1: ConfigSource = ??? val configSource2: ConfigSource = ??? val dbConfig = (string("USERNAME") from configSource1 zip int("PORT")).to[Config] from configSource2
In the above case
read(dbConfig)implies, zio-config tries to fetchUSERNAMEfrom configSource1, and if it fails (i.e, missing value) it goes and try with the global config which isconfigSource2. PORT will be fetched from configSource2.You can also try various sources for each field.
val configSource1: ConfigSource = ??? // Example: ConfigSource.fromMap(...) val configSource2: ConfigSource = ??? // Example: ConfigSource.fromTypesafeConfig(...) val dbConfig = (string("USERNAME") from configSource1.orElse(configSource2) zip int("PORT") from configSource2.orElse(configSource1)).to[Config] from configSource2
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
final
def
map[B](f: (A) ⇒ B): ConfigDescriptor[B]
Transform A to B, however usage of map disallows the usage of
writeback functionality.Transform A to B, however usage of map disallows the usage of
writeback functionality.Use
mapif we really don't care writing back the config to the sources in future -
final
def
mapEither[B](f: (A) ⇒ Either[String, B]): ConfigDescriptor[B]
Transform A to B that can fail, however usage of mapEither disallows the usage of
writeback functionality.Transform A to B that can fail, however usage of mapEither disallows the usage of
writeback functionality.Use
mapEitherif we really don't care writing back the config to the sources in future -
def
mapKey(f: (ConfigDescriptorModule.K) ⇒ ConfigDescriptorModule.K): ConfigDescriptor[A]
mapKey allows user to convert the keys in a ConfigDescriptor.
mapKey allows user to convert the keys in a ConfigDescriptor.
Example:
Consider you have a config that looks like this
case class Config(url: String, port: Int) object Config { val config = (string("dbUrl") zip int("dbPort")).to[Config] } val source = Map( "DB_URL" -> "abc.com", "DB_PORT" -> "9090" ) read(Config.config from ConfigSource.fromMap(source)) // will fail since the source doesn't have the keys dbUrl and dbPort, but it has only DB_URL and DB_PORT
The above config retrieval fails since the keys dbUrl and dbPOrt exist, but it has only DB_URL and DB_PORT. In this situation, instead of rewriting the config we can do
import zio.config._, ConfigDescriptor._ read(Config.config.mapKey(key => toSnakeCase(key).toUpperCase) from ConfigSource.fromMap(source)) // Right(Config("abc.com", 9090))
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
optional: ConfigDescriptor[Option[A]]
optionalfunction allows us to tag a configuration parameter as optional.optionalfunction allows us to tag a configuration parameter as optional. It implies, even if it's missing configuration will be a success.Example:
val port: ConfigDescriptor[Option[Int]] = int("PORT").optional
A more detailed example:
Here is a program that describes (or a ConfigDescriptor that represents) reading a
USERNAMEwhich is a String andPORTwhich is an Int, and load it to a case classConfigfinal case class Config(userName: String, port: Option[Int]) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT").optional).to[Config] }
The fact that it is an optional in error messages if config retrieval is a failure, and it's also used while documenting your configuration using
ConfigDocsModuleval dbConfigWithDoc: ConfigDescriptor[Config] = (string("USERNAME") ?? "db username" zip int("PORT") ?? "db port").to[Config]
import zio.config._, ConfigDescriptor._ val source = ConfigSource.fromMap(Map("USERNAME" -> "af")) read(Config.databaseConfig from source)
returns:
Config("af", None)
Similarly,
val source = ConfigSource.fromMap(Map("USERNAME" -> "af", "PORT" -> "8888")) read(Config.databaseConfig from source)
returns:
Config("af", Some(8888))
However, if you have given
PORT, but it's not an integer, then it fails giving you the error details.Within the error message, it will also specify the fact that the parameter is an optional parameter, giving you an indication that you can either fix the parameter, or you can completely skip this parameter.
Example:
import zio.config._, ConfigDescriptor._ val source = ConfigSource.fromMap(Map("USERNAME" -> "af", "PORT" -> "abc")) read(Config.databaseConfig from source)
returns:
╥ ╠══╗ ║ ║ ║ ╠─FormatError ║ ║ cause: Provided value is abc, expecting the type int ║ ║ path: PORT ║ ▼ ▼Another interesting behaviour, but we often forget about optional parameters is when there is a presence of a part of the set of the config parameters representing a product, where the product itself is optional.
Example:
final case class DbConfig(port: Int, host: String) object DbConfig { val dbConfig: ConfigDescriptor[Option[DbConfig]] = (int("PORT") zip string("HOST")).to[DbConfig].optional }
In this case if "PORT" is present in the source, but "HOST" is absent, then config retrieval will be a failure and not
None. Similarly, if "HOST" is present but "PORT" is absent, the config retrieval will be a failure and notNone.If both of the parameters are absent in the source, then the config retrieval will be a success and the output will be
None. If both of them is present, then output will beSome(DbConfig(..)) -
final
def
orElse(that: ⇒ ConfigDescriptor[A]): ConfigDescriptor[A]
orElseis used to represent fall-back logic when we describe config retrievals.orElseis used to represent fall-back logic when we describe config retrievals.Example:
val config: ConfigDescriptor[String] = string("token") <> string("password")
This is a description that represents the following: Try to retrieve the value of a parameter called "token", or else try to retrieve the value of parameter called "password"
We know
ConfigDescriptoris a program that describes the retrieval of a set of configuration parameters. In the below example, we can either depend on a configuration calledpasswordor atokenboth being of the same type, in this case, a String.Example:
final case class Config(tokenOrPassword: String, port: Int) object Config { val databaseConfig: ConfigDescriptor[Config] = (string("token") <> string("password") zip int("PORT")).to[Config] }
Note:
orElseis different fromorElseEither.While
orElsefall back to parameter which is of the same type of the original config parameter,orElseEithercan fall back to a different type giving usEither[A, B].orElsewill be useful in retrieving configuration that are represented as coproducted (sealed trait). However, it may become fairly verbose, such that usagezio-config-magnoliato derive the config automatically, will become a reasonable alternative. -
final
def
orElseEither[B](that: ⇒ ConfigDescriptor[B]): ConfigDescriptor[Either[A, B]]
orElseEitheris used to represent fall-back logic when we describe config retrievals.orElseEitheris used to represent fall-back logic when we describe config retrievals. UnlikeorElse, the fall-back config parameter can have a different type inorElseEither.Example:
val config: ConfigDescriptor[Either[Int, String]] = int("MONTH") <+> string("MONTH")
This is a description that represents the following: Try to retrieve the value of a MONTH as an
Int, and if there is a format error, try and retrieve it as aString.Detail:
We know
ConfigDescriptoris a program that describes the retrieval of a set of configuration parameters. In the below example, we can either depend on a configuration calledpasswordor atokenboth being of the same type, in this case, a String.Example:
Given:
final case class BasicAuth(username: String, password: String) final case class OAuth(clientId: String, secret: String) val basicAuth: ConfigDescriptor[BasicAuth] = (string("USERNAME") zip string("PASSWORD")).to[BasicAuth] val oAuth: ConfigDescriptor[OAuth] = (string("CLIENT_ID") zip string("SECRET")).to[OAuth] val myConfig: ConfigDescriptor[Either[BasicAuth, OAuth]] = basicAuth <+> oAuth
then,
val source = ConfigSource.fromMap(Map("USERNAME" -> "abc", "PASSWORD" -> "cde") read(myConfig from source)
returns:
Left(BasicAuth("abc", "def")
Similarly,
val source = ConfigSource.fromMap(Map("CLIENT_ID" -> "xyz", "SECRET" -> "afg==") read(myConfig from source)
returns:
Right(OAuth("xyz", "afg==")
-
lazy val
sources: Set[ConfigDescriptorModule.ConfigSource]
Fetch all the sources associated with a ConfigDescriptor.
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
to[B <: Product](implicit conv: TupleConversion[B, A]): ConfigDescriptor[B]
Convert a
ConfigDescriptor[A]to a config descriptor of a case classConvert a
ConfigDescriptor[A]to a config descriptor of a case classThis works when
Ais a single value andBis a single parameter case class with the same type of parameter, or ifAis an tuple andBis a case class with matching number of parameters and the same types.See the following example of reading a
USERNAMEwhich is a String andPORTwhich is an Int, and load it to a case classConfig:final case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT")).to[Config] }
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
final
def
transform[B](to: (A) ⇒ B, from: (B) ⇒ A): ConfigDescriptor[B]
Given
AandB,f: A => B, andg: B => A, thentransformallows us to transform aConfigDescriptor[A]toConfigDescriptor[B].Given
AandB,f: A => B, andg: B => A, thentransformallows us to transform aConfigDescriptor[A]toConfigDescriptor[B].Example :
transformis useful especially when you define newtypes.final case class Port(port: Int) extends AnyVal val config: ConfigDescriptor[Port] = int("PORT").transform[Port](Port.apply, _.int)
While
to: A => B(in this case,Int => Port) is used to read to aPortcase class,from: B => A(which is,Port => Int) is used when we want to writePortdirectly to a source representation.Example:
import zio.config.typesafe._ // as toJson is available only through zio-config-typesafe module val writtenBack: Either[String, PropertyTree[String, String]] = write(config, Port(8888)) val jsonRepr: Either[String, String] = writtenBack.map(_.toJson) // { "port" : "8888" } val mapRepr: Either[String, Map[String, String]] = writtenBack.map(_.flattenString()) // Map("port" -> "8888")
-
final
def
transformOrFail[B](to: (A) ⇒ Either[String, B], from: (B) ⇒ Either[String, A]): ConfigDescriptor[B]
Given
AandB,transformOrFailfunction is used to convert aConfigDescriptor[A]toConfigDescriptor[B].Given
AandB,transformOrFailfunction is used to convert aConfigDescriptor[A]toConfigDescriptor[B].It is important to note that both
toandfrois fallible, allowing us to represent almost all possible relationships.Example:
Let's define a simple
ConfigDescriptor, that talks about retrieving aS3Path( a bucket and prefix in AWS s3). Given you want to retrieve an S3Path from ConfigSource. Given a string, converting it to S3Path can fail, and even converting S3Path to a String can fail as well.import java.time.DateTimeFormatter import java.time.LocalDate final case class S3Path(bucket: String , prefix: String, partition: LocalDate) { def convertToString(partitionPattern: String): Either[String, String] = Try { DateTimeFormatter.ofPattern(partitionPattern).format(partition) }.toEither .map(dateStr => s"${bucket}/${prefix}/${dateStr}").swap.map(_.getMessage).swap } object S3Path { def fromStr(s3Path: String): Either[String, S3Path] = { val splitted = s3Path.split("/").toList if (splitted.size > 3) Left("Invalid s3 path") else for { bucket <- splitted.headOption.toRight("Empty s3 path") prefix <- splitted.lift(1).toRight("Invalid prefix, or empty prefix in s3 path") partition <- splitted.lift(2).toRight("Empty partition").flatMap(dateStr => LocalDate.parse(dateStr)) } yield S3Path(bucket, prefix, partition) } } val s3PathConfig: ConfigDescriptor[S3Path] = string("S3_PATH").transformEither[S3Path](S3Path.fromStr, _.convertToString("yyyy-MM-dd"))
- final def transformOrFailLeft[B](f: (A) ⇒ Either[String, B])(g: (B) ⇒ A): ConfigDescriptor[B]
- final def transformOrFailRight[B](f: (A) ⇒ B, g: (B) ⇒ Either[String, A]): ConfigDescriptor[B]
-
final
def
unsourced: ConfigDescriptor[A]
Untag all sources associated with a
ConfigDescriptor.Untag all sources associated with a
ConfigDescriptor.As we know
ConfigDescriptorrepresents a program that describes the retrieval of config parameters. In fact, the same program can be used to write back the config in various shapes.Either case, a
ConfigDescriptorcan exist without aSourceattached.Example:
val stringConfig: ConfigDescriptor[String] = string("USERNAME")
Later on we can read the config by attaching a source.
val result = read(stringConfig from ConfigSource.fromMap(Map.empty))
However, you can attach a source to the configDescriptor at an earlier stage.
For example:
val stringConfig: ConfigDescriptor[String] = string("USERNAME") from ConfigSource.fromMap(Map.empty)
Later on, you can simply read it using:
val result = read(stringConfig)Using
unsourced, you can now untag the source fromstringConfig.val stringConfigNoSource: ConfigDescriptor[String] = stringConfig.unsourced
This can be useful in test cases where you want to remove a source and attach a different source.
Example:
val testSource: ConfigSource = ConfigSource.fromMap(Map(..)) val result = stringConfig.unsourced from testSource
-
final
def
updateSource(f: (ConfigDescriptorModule.ConfigSource) ⇒ ConfigDescriptorModule.ConfigSource): ConfigDescriptor[A]
updateSourcecan update the source of an existingConfigDescriptorupdateSourcecan update the source of an existingConfigDescriptorExample:
val configSource1 = ConfigSource.fromMap(Map.empty) val configSource2 = ConfigSource.fromMap(Map("USERNAME" -> "abc")) val config = string("USERNAME") from configSource1 val updatedConfig = config updateSource (_ orElse configSource2)
In the above example, we update the existing ConfigDescriptor to try another ConfigSource called configSource2, if it fails to retrieve the value of USERNAME from configSource1.
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... ) @native()
-
final
def
zip[B, C](that: ⇒ ConfigDescriptor[B])(implicit Z: WithOut[A, B, C]): ConfigDescriptor[C]
zip is a ConfigDescriptor builder.
zip is a ConfigDescriptor builder. We know
ConfigDescriptoris a program that describes the retrieval of a set of configuration parameters.Below given is a
ConfigDescriptorthat describes the retrieval of a single config.val port: ConfigDescriptor[String] = string("PORT")
However, in order to retrieve multiple configuration parameters, we can make use of
zip.Example:
final case class Config(userName: String, port: Int) object Config { val dbConfig: ConfigDescriptor[Config] = (string("USERNAME") zip int("PORT")).to[Config] }
Deprecated Value Members
-
def
apply[B](app: (A) ⇒ B, unapp: (B) ⇒ Option[A]): ConfigDescriptor[B]
- Annotations
- @deprecated
- Deprecated
(Since version 2.0) Use .to[B] if the transformation is to a case class. If not use use transform methods