safe-config

Safe Config provides a safe and convenient wrapper around Typesafe's Config library.

License

License

Categories

Categories

config Application Layer Libs Configuration
GroupId

GroupId

com.kinja
ArtifactId

ArtifactId

safe-config_2.11
Last Version

Last Version

1.1.2
Release Date

Release Date

Type

Type

jar
Description

Description

safe-config
Safe Config provides a safe and convenient wrapper around Typesafe's Config library.
Project URL

Project URL

https://github.com/gawkermedia/safe-config
Project Organization

Project Organization

com.kinja
Source Code Management

Source Code Management

https://github.com/gawkermedia/safe-config

Download safe-config_2.11

How to add to project

<!-- https://jarcasting.com/artifacts/com.kinja/safe-config_2.11/ -->
<dependency>
    <groupId>com.kinja</groupId>
    <artifactId>safe-config_2.11</artifactId>
    <version>1.1.2</version>
</dependency>
// https://jarcasting.com/artifacts/com.kinja/safe-config_2.11/
implementation 'com.kinja:safe-config_2.11:1.1.2'
// https://jarcasting.com/artifacts/com.kinja/safe-config_2.11/
implementation ("com.kinja:safe-config_2.11:1.1.2")
'com.kinja:safe-config_2.11:jar:1.1.2'
<dependency org="com.kinja" name="safe-config_2.11" rev="1.1.2">
  <artifact name="safe-config_2.11" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.kinja', module='safe-config_2.11', version='1.1.2')
)
libraryDependencies += "com.kinja" % "safe-config_2.11" % "1.1.2"
[com.kinja/safe-config_2.11 "1.1.2"]

Dependencies

compile (4)

Group / Artifact Type Version
org.scala-lang : scala-compiler jar 2.11.12
org.scala-lang : scala-library jar 2.11.12
com.typesafe : config jar 1.3.4
org.scala-lang.modules : scala-collection-compat_2.11 jar 2.1.1

test (1)

Group / Artifact Type Version
org.scalatest : scalatest_2.11 jar 3.0.8

Project Modules

There are no modules declared in this project.

Safe Config

Safe Config provides a safe and convenient wrapper around Typesafe's Config library.

Quick Start

Add the following to your build.sbt file:

libraryDependencies ++= Seq(
  "com.kinja" %% "safe-config" % "1.1.2",
  compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full))

Create your first config object:

import com.kinja.config.safeConfig
import play.api.Play.configuration.{ underlying => playConf }

@safeConfig(playConf)
object Config {
   
   val dbConfig = for {
      conf  <- getConfig("db")
      read  <- conf.getString("read")
      write <- conf.getString("write")
   } yield DbConfig(read, write)

   val languages = getStringList("application.languages")

   val secret = getString("application.secret")
}

final case class DbConfig(readConnection : String, writeConnection : String)
// In Global.scala
override def onStart(app: Application): Unit = {
  Config
  ...
}

How To Use

The safeConfig annotation marks a configuration object. Within the configuration object all errors are handled automatically and accessors are created exposing the pure values. Additionally, configuration objects expose the ConfigApi interface (select "Visibility: All").

All config values in the configuration object are eagerly evaluated and if any are the wrong type or missing, an exception is thrown indicating the problems with reading the config file.

In order to catch these errors as soon as possible, you should reference your config objects during your application's startup.

Use With Classes

As of version 1.1.0, Safe Config can be used to annotate a class as well. This works well with Play 2.4's dependency injection. Instead of passing the underlying play config to the macro directly, pass the name of the identifier it is available at within the class object.

import com.kinja.config.safeConfig

import play.api._, ApplicationLoader.Context

@safeConfig("rawConfig")
class Bootstrap(context: Context) extends BuiltInComponentsFromContext(context) {
   private val rawConfig = configuration.underlying
   
   val dbConfig = for {
      conf  <- getConfig("db")
      read  <- conf.getString("read")
      write <- conf.getString("write")
   } yield DbConfig(read, write)

   val languages = getStringList("application.languages")

   val secret = getString("application.secret")
}

Applicative Style

In addition to the normal map and flatMap methods which allow you to use for comprehensions in your configuration, Safe Config provides a <*> operator which can be used to write shorter code.

  val dbConfig = (BootupErrors((DbConfig.apply _).curried)
    <*> conf.getString("db.read")
    <*> conf.getString("db.write"))

API Documentation

The full API documentation is available here.

How It Works

The example given above will expand to the following:

import com.kinja.config.safeConfig
import play.api.Play.configuration.{ underlying => playConf }

object Config extends com.kinja.config.ConfigApi {
   import com.kinja.config._
   val root = BootupErrors(LiftedTypesafeConfig(playConf))

   private final class $Extractor(a : DbConfig, b : List[String], c : String)
   private object $Extractor {
      def construct : DbConfig => List[String] => String => $Extractor =
         a => b => c => new $Extractor(a, b, c)
   }
   private val dbConfig = getConfig("db")

   private val $orig_dbConfig : BootupErrors[DbConfig] = for {
      conf  <- dbConfig
      read  <- conf.getString("read")
      write <- conf.getString("write")
   } yield DbConfig(read, write)
   private val $orig_languages : BootupErrors[List[String]] = getStringList("application.languages")
   private val $orig_secret : BootupErrors[String] = getString("application.secret")
   
   private val $Extractor_instance = (BootupErrors($Extractor.construct)
      <*> $orig_dbConfig
      <*> $orig_languages
      <*> $orig_secret
   ).fold(errs => throw new BootupErrorsException(errs), a => a)
   
   val dbConfig = $Extractor_instance.a
   val languages = $Extractor_instance.b
   val secret = $Extractor_instance.c
}

final case class DbConfig(readConnection : String, writeConnection : String)

Limitations

Due to the way type-checking occurs within the macro, forward references are not allowed within the annotated object.

Because of a bug in Macro Paradise, annotation of objects nested within a class does not work.

com.kinja

Gizmodo Media

Versions

Version
1.1.2
1.1.1
1.1.0
1.0.0