4 Easy steps to load configuration with pure-config

Reading Time: 3 minutes

Configuration plays a very important role in application deployment. It is basicaly used to define environment variables and helps in deploying same code in different environment. In this blog we will be discussing 4 easy steps to load configuration with pure-config.

Typically the configuration contains connection strings, connection details to external services and application settings etc. Typesafe config is one of the most popular library to load configurations. On the other hand Pure config is a scala library for loading the configuration. Under the hood, it reads typesafe config written in HOCON, Java .properties or JSON to native scala classes. It provides boilerplate free way to load application configuration. It supports sealed traits, case classes, collections, optional values and other types. Apart from it, pure config also supports custom types out of the box.

Why Pure-Config?

As we know, typesafe config allows you to read individual fields from config. Its developers responsibility to read them and maintain them properly. There is a possibility that you are reading the same config at multiple places. The pure config provide a typesafe way to read your configuration and reduces bolireplating. Lets look at the types supported by pure-config in next section.

Type supported by pure config:

Pure config provide support for many build in types and most of them are from standard Java and Scala libraries. There is no specefic step needs to perform while loading config for these types.

Some of the most used types are:

  • String, Boolean, Double, Int, Long, Short, Byte, Char, URL, URI, Duration, FiniteDuration, java.lang.Enum, java.time
  • java.io.File, java.util.UUID, java.nio.file.Path, java.util.regex.Pattern and scala.util.matching.Regex.
  • java.math.BigDecimal, java.math.BigInteger, scala.math.BigDecimal, and scala.math.BigInt.
  • Pure config also handles collections like Option, Map.

Apart from it, pure config also support new types. It also allows overwriting the behaviour of the a given type.

Error Handling:

Pure config also provide error handling. There are several possible failure reasons and most common are as follows:

There are several potential reasons for a failure. The most common being:

  • CannotConvert: A general, uncategorized reason
  • KeyNotFound: A required key was not found
  • WrongType: A config value has a wrong type

Pure config provide the appropriate error logs to debug the errors.

Sample Application for Pure Config:

Here is a sample application that uses pure config library to fetch the configuration. Lets start with build.sbt file:

Build.sbt:

Here is build.sbt file for the pure-config dependency:

name := "pure-config-sample"

version := "1.0"

scalaVersion := "2.11.11"

libraryDependencies ++= Seq(
  "org.scalatest" %% "scalatest" % "3.0.4",
  "com.github.pureconfig" %% "pureconfig" % "0.13.0"
)

Application.conf:

Here is a sample application.conf file that contains sample application configuration and typical akka config. As you can see it contains normal strings, custom types, Sets, Int and time durations as well.

// Application configuration
host = "localhost"
port = 8081
use-tcp = true
auth-methods = [
  { type = "private-key", pk-file = "/home/girish/auth" },
  { type = "login", username = "pureconfig", password = "password" }
]
// Akka config
akka {
  cluster {
    seed-nodes = ["localhost:8181", "localhost:8182"]
    seed-node-timeout = 5s
    retry-unsuccessful-join-after = 10s
    shutdown-after-unsuccessful-join-seed-nodes = off
    down-removal-margin = off

    downing-provider-class = ""
    quarantine-removed-node-after = 5s
    allow-weakly-up-members = on
    roles = ["processor"]
    run-coordinated-shutdown-when-down = on
    min-nr-of-members = 1
    log-info = on
    log-info-verbose = off
    jmx.enabled = on
  }
}

Config Extractor:

Here is the code snippet to fetch the config from aplication.conf file. Here the ConfigSource is an in-build trait that helps in loading the configuration. All config loading methods are lazy and defer resolution of references until needed.

import pureconfig.ConfigSource
import pureconfig._
import pureconfig.generic.auto._

object Configuration {

  val serviceConf: ServiceConf = ConfigSource.default.load[ServiceConf] match {
    case Right(conf) => conf
    case Left(error) => throw new Exception(error.toString())
  }

}

Application:

Here is the sample appliation to print the loaded configuration:

package com.knoldus.config.app

import com.knoldus.config.conf.Configuration

object SampleApplication extends App {
  val config = Configuration.serviceConf
  println("Application configuration... " + config)
}

Code Repo:

For the complete code sample you may visit the Git Repo.

Sample Output:

You can run this application using following command:

$ sbt run

Output:

Application configuration....... ServiceConf(localhost,Port(8081),true,List(PrivateKey(/home/girish/auth), Login(pureconfig,password)),Akka(Cluster(Set(localhost:8181, localhost:8182),5s,10s,off,off,,5s,on,List(processor),on,1,on,off,Jmx(on)))) 

As you can see the code magically converts all our config into a scala case class. You can use this complex case class as constant object with type safety. The additional advantage you get with this approach is that you get a compile time error. Unlike the typesafe config where you get a run time error if any config is missing. At the same time you dont need to play with optional fields while fetching configuration.

Here are a few more reads to know more about pure config like Avoiding boiler plate with pure config and What to do for overriding the PureConfig behavior in Scala?

Hope you enjoyed the post. Thanks for reading!

Knoldus-blog-footer-image

Written by 

Girish is a Software Consultant, with experience of more than 3.5 years. He is a scala developer and very passionate about his interest towards Scala Eco-system. He has also done many projects in different languages like Java and Asp.net. He can work in both supervised and unsupervised environment and have a craze for computers whether working or not, he is almost always in front of his laptop's screen. His hobbies include reading books and listening to music. He is self motivated, dedicated and focused towards his work. He believes in developing quality products. He wants to work on different projects and different domains. He is curious to gain knowledge of different domains and try to provide solutions that can utilize resources and improve performance. His personal interests include reading books, video games, cricket and social networking. He has done Masters in Computer Applications from Lal Bahadur Shastri Institute of Management, New Delhi.