Skip to main content
Version: 2.x

Automatic Validations

By bringing in zio-config-refined module, you get validations for your config parameters almost for free. zio-config elegantly integrates with Refined library for you to achieve this with same ergonomics.

If you are not familiar with refined library, refer https://github.com/fthomas/refined.

There are various ways that zio-config can interact with refined library. Take a look at zio.config.refined package.

 import zio.Config
import zio.ConfigProvider
import zio.config._, refined._

A few examples are given below.

Basic Example​

 import eu.timepit.refined.types.string.NonEmptyString

case class Jdbc(username: NonEmptyString, password: NonEmptyString)

val jdbc: Config[Jdbc] =
(refineType[NonEmptyString]("username") zip
refineType[NonEmptyString]("password")).to[Jdbc]

ConfigProvider.fromMap(Map("username" -> "", "password" -> "")).load(jdbc)

Direct Interaction with Refined Predicates​

If you need to directly interact with Predicates (ex: NonEmpty), then refine[A, P] method is useful.

 import eu.timepit.refined._, api._, string._, collection._

type NonEmptyString = String Refined NonEmpty

val refinedConfig: Config[NonEmptyString] =
refineType[NonEmptyString]("USERNAME")

// Another way of doing it is
val urlConfig: Config[Refined[String, Url]] =
refine[String, Url]("URL")

// refineType takes a fully formed type (String Refined NonEmpty) where as refine allows you to play with the predicate directly (NonEmpty)

Derive from existing Config​

Of various methods available in zio.config.refined package, the most interesting one is being able to get a refined type out of an already derived Config. This shows the composable nature of zio-config.

Take a look at the below example

 import eu.timepit.refined._, api._, numeric._, collection._
import zio.config.magnolia.deriveConfig

case class MyConfig(url: String, port: Int)

val configs: Config[List[MyConfig]] =
Config.listOf("databases", deriveConfig[MyConfig])

// A list of database configs, such that size should be greater than 2.
val databaseList: Config[Refined[List[MyConfig], Size[Greater[W.`2`.T]]]] =
refine[Size[Greater[W.`2`.T]]](configs)

Auto-Derivation and Refined​

You can also use auto derivations with refined.

import zio.ConfigProvider
import eu.timepit.refined.W
import eu.timepit.refined.api.Refined
import eu.timepit.refined.collection.{ NonEmpty, Size }
import zio.config.magnolia.deriveConfig

object RefinedReadConfig extends App {
case class RefinedProd(
ldap: Refined[String, NonEmpty],
port: Refined[Int, GreaterEqual[W.`1024`.T]],
dbUrl: Option[Refined[String, NonEmpty]]
)

val configMap =
Map(
"LDAP" -> "ldap",
"PORT" -> "1999",
"DBURL" -> "ddd"
)

val result =
ConfigProvider.fromMap(configMap).load(deriveConfig[RefinedProd].mapKey(_.toUpperCase))

// RefinedProd(ldap,1999,Some(ddd))
}