Skip to content

qdzo/ceylon-config

Repository files navigation

ceylon-config

A Ceylon Library for managing configuration from several sources, including

  • config files
  • env variables
  • java system-properties

This library inspired by The Twelve-Factor App and yogthos/config project.

Configuration is resolved in next order:

  1. config json/toml file in current dir
  2. profile json/toml file
  3. custom config file json/toml, specified by cmd parameter --config
  4. Environment variables
  5. cmd parameters
  6. java-system properties

Each next level overrides definitions from earlier levels.

toml files has more higher priority than json.

Install

Add dependency to your module.ceylon file

import com.github.qdzo.config "0.2.0";

Usage

Library looks for the config file in current dir and profiles dirs. After that it loads system environment variables, cmd parameters, system properties and merges them in one HashMap<String,String> that accessible as env top-level object.

Use Configuration file

Create config.json file in project root.

{
  "database": {
    "host": "localhost",
    "port": 5144,
    "user": "admin",
    "password": "secret"
  }
}

Use env object to obtain variables.

import com.github.qdzo.config { env }

shared void run() {
    String dbHost = env.getString("database.host");            // asserts value existence
    Integer dbPort = env.getInteger("database.port");          // asserts existence and try parse-integer 
    String? dbUser = env.getStringOrNull("database.user");     // optional parameter
    String? dbPass = env["database.password"];                 // env satisfies Map<String,String>
    
    value connection = connectDb(dbHost, dbPort, dbUser, dbPass);
    ...
}

Use system environment variables or cmd parameters

You can override config variables by specifying system environment variables or cmd parameters

Set environment before application start-up

export DATABASE_HOST=192.168.0.10
export DATABASE_HOST=4000

Or set cmd parameters with ceylon run command

ceylon run app.module --database-host 192.168.0.10 -database.port=4000

Also you can specify custom config file

ceylon run app.module --config=my/custom/config.toml

Mulitple configurations

Setting up mutliple configurations is done by profiles dirs.

Ceylon doesn't force us to use any kind of configuration for different dev environments.

Profile dir is a dir that placed in path {project_root}/config/{profile-name}.

You need to create config dir in project root and then create dev, test stage (whatever...) dirs nested in config dir.

In each of these dirs create config file: config.json or config.toml.

You must get such paths in project root:

  • config/dev/config.json
  • config/test/config.toml
  • config/test/config.json

To specify profile config you must set environment variable PROFILE to needed profile.

export PROFILE=dev

NOTE: all variables that gathered from different sources are transformed to one format:

  • all chars lower-cased
  • hyphen (-) and underscore (_) replaced with dot (.)

This gives you some advantages:

  • a freedom to specify variables according standards (upper-cased with underscore in env, lower-cased with dot in java-properties)
  • to use variables without fear to forget they format.

The library prints warnings when it formats variables, so be attentive

Caveats:

ceylon-config doesn't support arrays in json: it converts them to string. This is made to exclude ugly and buggy variable-names followed by index - foo.1, foo.2.name.

Because position is matter in sequence.

Advanced

Using annotations to setup config-Classes and instantiate them

It's convenient to use some class as configuration. You can annotate fields of that class with envVar("varname") annotation and then get instantce of that class with specified parameters from the environment variables.

Example:

class Config(
    envVar("server.host")
    shared String host,

    envVar("server.port")
    shared Integer port,
    
    envVar("server.user")
    shared String user = "test-user",

    envVar("server.pass")
    shared String? pass = null,
) {}

shared void run() {
    value conf = configure<Config>(); 
    value connection = connectDb(conf.host, conf.port, conf.user, conf.pass);
    ...
}

Rules to create such config class:

  • Fields must be one(or union) of the basic types (Boolean, Integer, Float, String, Date, Time, DateTime) or sequence/iterable of them.
  • Fields with default values are treated as optional fields, and may not have value in environment.
  • If some variable is not exists in the environment then EnvironmentVariableNotFoundException will be thrown while configure<Type>.

Using env in non-run method

If you want to use env variables somewhere in the project and you want to be sure that variable present at application startup, you would annotate your method with requiredEnv annotation and call checkEnvRequirements in run method.

requiredEnv("web.host", "web.port") // method required some envirnment variables
shared startServer() {
    String host = env.getString("web.host");
    Integer port = env.getInteger("web.port");
    value server = newServer({});
    server.start(SocketAddress(host, port));
}

shared void run() {
    checkEnvRequirements(`module`); // search for `requredEnv` annotaion in current-module and check env existence
    ...
    Thread.sleep(10_000)
    serverStart();
}

Changelog

0.2.1

  • Fix correct order of config loading.
    • Swap 'set' with 'HashSet' and 'linked stability'
  • Swap config loading priority of custom config and env variables

0.2.0

  • Improved injector capabilities
    • Add support for union-types (String|Integer|Null)
    • Add support for heterogeneous sequences ([String|Integer*])
  • Add internal sanitizers(lowercase) to envVar parameter and get* methods

    Now you can call get* methods and use envVar annotation with camelCase strings

0.1.3

  • Replace AssertionErrors with Custom Exceptions

0.1.1

  • rename annotation envVar

0.1.0

  • Create annotation-based injector
  • Create requirenmentChecker

0.0.1

  • Initial release.

Licence

Distributed under the Apache License, Version 2.0.

About

Ceylon Library for managing app configuration.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published