config derivation with ZIO config and Magnolia
Config derivation with ZIO config and Magnolia.
Automatic config derivation is a very convenient way to read a config file into a lot of case classes.
Listing 1. app.conf
coffee {
ingredients = "coffeeBeans,hot water"
brewTime = 60 seconds
}
Listing 2. DeriveConfigApp.scala
package config
import zio.config._
import zio.config.magnolia._
import zio.config.typesafe.TypesafeConfigProvider
import zio.{Config, ZIO, ZIOAppDefault}
import java.nio.file.Paths
object DeriveConfigApp extends ZIOAppDefault {
case class CoffeeConfig(ingredients: List[String], brewTime: zio.Duration)
case class AppConfig(coffee: CoffeeConfig)
implicit val appConfigDescriptor: Config[AppConfig] = deriveConfig[AppConfig]
def readResource[A](filePath: String)(implicit config: Config[A]): ZIO[Any, Config.Error, A] = {
val file = Paths.get(getClass.getClassLoader.getResource(filePath).toURI).toFile
val c = config.from(TypesafeConfigProvider.fromHoconFile(file))
read(c)
}
def run = for {
appConfig <- readResource[AppConfig]("app.conf")
coffee = appConfig.coffee
_ <- ZIO.logInfo("start brewing coffee")
_ <- ZIO.foreach(coffee.ingredients)(i => ZIO.logInfo(s"adding ingredient: $i"))
_ <- ZIO.logInfo(s"waiting for ${coffee.brewTime.getSeconds} seconds")
_ <- ZIO.logInfo(s"done. enjoy!")
} yield ()
}
But as we can see in this output, it’s not always exactly as we want it:
start brewing coffee adding ingredient: coffeeBeans,hot water waiting for 60 seconds done. enjoy!
If we want to read the comma-separated String as a List, we’ll have to provide our own Config descriptor. One might be tempted to add this:
implicit val stringListDescriptor: Config[List[String]] = deriveConfig[String].map(_.split(",").toList)
However, this does not work together with deriveConfig[AppConfig]
.
To make it available for automatic derivation, we’ll have to add it as a DeriveConfig
:
implicit val stringListDescriptor: DeriveConfig[Set[String]] = DeriveConfig[String].map(_.split(","))
implicit val appConfigDescriptor: Config[AppConfig] = deriveConfig[AppConfig]
Now all is well:
start brewing coffee adding ingredient: coffeeBeans adding ingredient: hot water waiting for 60 seconds done. enjoy!