Skip to content

Instantly share code, notes, and snippets.

@pathikrit
Last active March 5, 2020 14:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pathikrit/a0aab4b5da4493baf2dac79a38f11945 to your computer and use it in GitHub Desktop.
Save pathikrit/a0aab4b5da4493baf2dac79a38f11945 to your computer and use it in GitHub Desktop.
Better Config
import scala.util.control.NonFatal
import better.files.Scanner.Read
/**
* Extend this trait to create your application config
*
* Pros of this approach:
* 1) Library free approach - only 15 lines of dependency free "library" (four one-line defs for you to override)
* 2) Failures happen when the Config object is loaded instead of when a config value is accessed
* 3) Strongly typed
* 4) Overrides can be provided using both system properties and/or environment variables
* 5) No more config file DSL - your configs are in plain old Scala
* 6) Easily understandable error messages
* 7) You can define your own Read instances to read complex objects as configs
*/
trait Config {
protected def configValue(key: String): Option[String] =
sys.props.get(key) orElse sys.env.get(key)
protected def config[A](key: String)(implicit read: Read[A]): Option[A] =
configValue(key) map {c =>
try {
read(c)
} catch {
case NonFatal(e) => throw new IllegalArgumentException(s"Could not parse config value=$c for key=$key", e)
}
}
protected def config[A: Read](key: String, defaultValue: => A): A =
config(key).getOrElse(defaultValue)
protected def configOrError[A: Read](key: String, errorMsgPrefix: String = "Missing config"): A =
config(key, throw new NoSuchElementException(s"$errorMsgPrefix key=$key"))
}
// usage
object MyConfig extends Config {
object db {
val host: String = config("db.host", "postgres.rds.com")
val port: Int = config("db.port", 9099)
val pass: String = configOrError("db.password")
}
object aws {
val secret: String = config("aws.secret").getOrElse(new AWSPasswordManager().load().getPassword())
}
}
// access
val driver = new PsqlDriver(host = MyConfig.db.host, host = MyConfig.db.port)
@alwins0n
Copy link

alwins0n commented Mar 4, 2020

hey nice, but its not library free if it imports, well, a library

@pathikrit
Copy link
Author

@alwins0n: It just imports a Read typeclass which many common libraries like cats and better-files have it. You can just implement the Read typeclass yourself then if you want truly library free - it will be 15 more lines of code then...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment