Kitura

APIDoc Build Status - Master macOS Linux Apache 2 Slack Status

Configuration

Configuration is a Swift package for managing application configurations. Using Configuration, an application can easily load and merge configuration data from multiple sources and access them from one central configuration store.

Configuration supports configuration keys as paths. That is, a key is a qualified path selector written in the [parent]<separator>[child] syntax. This allows applications to retrieve configuration objects at any level of specificity.

Version

The latest release of Configuration (v3.x.x) runs on Swift 4.0 and newer, on both macOS and Ubuntu Linux.

Usage

Add dependencies

Add Configuration to the dependencies within your application’s Package.swift file. Substitute "x.x.x" with the latest Configuration release.

.package(url: "https://github.com/IBM-Swift/Configuration.git", from: "x.x.x")

Add Configuration to your target’s dependencies:

.target(name: "example", dependencies: ["Configuration"]),

Initialize Configuration

The core of the Configuration package is the ConfigurationManager class. To manage your application’s configurations, first create an instance of the ConfigurationManager class.

import Configuration

let manager = ConfigurationManager()

Using the ConfigurationManager instance, you can then load and retrieve configurations:

manager.load(file: "config.json").load(.environmentVariables)
let value = manager["path:to:configuration:value"]

Loading Configuration Data

Configuration has many methods to load configuration data.

NOTE: In all cases, configuration key paths are case sensitive.

From a Raw Any Object

manager.load([
    "hello": "world",
    "foo": [
        "bar": "baz"
    ]
])

From Command-line Arguments

manager.load(.commandLineArguments)

To inject configurations via the command-line at runtime, set configuration values when launching the executable, like so:

./myApp --path.to.configuration=value

You can set your preferred argument prefix (default: --) and path separator (default: .) strings when instantiating ConfigurationManager.

From Environment Variables

manager.load(.environmentVariables)

Then, to use it in your application, set environment variables like so:

PATH__TO__CONFIGURATION=value

You can set your preferred path separator (default: __) string when instantiating ConfigurationManager.

From a Data Object

let data = Data(...)
manager.load(data: data)

From a File

manager.load(file: "/path/to/file")

By default, the file argument is a path relative from the location of the executable (i.e., .build/debug/myApp); if file is an absolute path, then it will be treated as such. You can change the relative-from path using the optional relativeFrom parameter, like so:

// Resolve path against PWD
manager.load(file: "../path/to/file", relativeFrom: .pwd)

// or

// Resolve path against a custom path
manager.load(file: "../path/to/file", relativeFrom: .customPath("/path/to/somewhere/on/file/system"))

NOTE: The following relativeFrom options, .executable (default) and .pwd, will reference different file system locations if the application is run from inside Xcode than if it is run from the command-line. You can set a compiler flag, i.e. -DXCODE, in your xcodeproj and use the flag to change your configuration file loading logic.

NOTE: Because BasePath.project depends on the existence of a Package.swift file somewhere in a parent folder of the executable, changing its location using swift build --build-path is not supported.

From a URL

let url = URL(...)
manager.load(url: url)

NOTE: The URL MUST include a scheme, i.e., file://, http://, etc.

From Multiple Sources

You can chain these methods to load configuration data from multiple sources all at once. If the same configuration key exists in the multiple sources, the one most recently loaded will override the ones loaded earlier. In this simple example,

manager.load(["foo": "bar"]).load(["foo": "baz"])

the value for foo is now baz because ["foo": "baz"] was more recently loaded than ["foo": "bar"]. The same behavior applies to all other load functions.

NOTE: Currently, Configuration only supports JSON and PLIST formats for resources loaded from Data, file, or URL. You can write a custom deserializer to parse additional formats.

Accessing Configuration Data

To get individual configuration values after they have been loaded, use:

manager["path:to:configuration"]

The configuration store is represented as a tree, where the path elements in keys are delimited by colons (:). For instance, the key VCAP_SERVICES:cloudantNoSQLDB:0:credentials:host would traverse into VCAP_SERVICES, cloudantNoSQLDB, array index 0, credentials, and then host to grab the value. Here is a JSON example of the structure:

{
    "VCAP_SERVICES": {
        "cloudantNoSQLDB": [
            {
                "credentials": {
                    "host": <value-goes-here>
                }
            }
        ]
    }
}

The value returned is typed as Any?. Therefore, it’s important to cast the value to the type you want to use. For instance:

let stringValue = manager["VCAP_SERVICES:cloudantNoSQLDB:0:credentials:host"] as? String

You can also retrieve configuration objects via partial paths; for example, if you use manager["VCAP_SERVICES:cloudantNoSQLDB:0:credentials"], the result is a dictionary of the key-values in credentials.

To get all configuration values in the configuration store, use:

manager.getConfigs()

The return value is a raw representation of all configuration values currently in the configuration store.

Acknowledgements

Configuration was inspired by nconf, a popular NodeJS hierarchical configuration manager.

API Documentation

For more information visit our API reference.

License

This library is licensed under Apache 2.0. Full license text is available in LICENSE.