API Usage

Path: /src/index.coffee compiled to /lib/index.js

This package will give you an easy way to load and use configuration settings into your application or module.

Setup Origin

The origin is the place the configuration data comes from. For alinex-config you have the possibility to specify multiple search paths, you can also overload configurations with another file in higher priority and combine values from different files together. So the specification of the origin is the main part and is the base to build the registry data.

Origin Structure

To setup the origin for the configuration module you have to extend the origin list by adding a new origin object.

The single origin object describes where to find the configuration, what to use and where to put them in the final data structure. Origin Import is the definition of origins to add to the internal list.

An object with the following keys allowed: uri, parser, filter, path, type. The following entries have a specific format:

uri

URI is the path to search with possible placeholders.

A text entry in which all control characters will be removed. It has to be at least 1 characters long.

parser

Parser is the type to use for parsing the data.

A text entry which is optional. All control characters will be removed. Only the values: ‘csv’, ‘yml’, ‘yaml’, ‘js’, ‘javascript’, ‘json’, ‘bson’, ‘cson’, ‘coffee’, ‘xml’, ‘ini’, ‘properties’ are allowed.

filter

Filter is the part of the structure to use.

A text entry which is optional. All control characters will be removed. It has to be at least 1 characters long.

path

Path is the position where to put it in the data structure.

A text entry which is optional. All control characters will be removed. It has to be at least 1 characters long.

type

Type is the type of data in this origin.

A text entry which is optional. All control characters will be removed. Only the values: ‘config’, ‘template’ are allowed.

URI Type

The following URI types are possible here:

  • No Protocol => using the file protocol
  • file:// => load from local file
  • http:// or https:// => load from web service

File search

You may access files absolute from root or relative from current directory:

file:///etc/myapp.yml   # absolute path
/etc/myapp.yml          # shortcut

file://config/myapp.yml # relative path
config/myapp.yaml       # shortcut

You can search by using asterisk as placeholder or a double asterisk to go multiple level depth:

/etc/myapp.*            # search for any extension
/etc/myapp/*.yml        # find all files with this extension
/etc/myapp/*            # find all files in the directory
/etc/myapp/* /*.yml     # find one level depth
/etc/myapp/**           # find all files in directory or subdirectories
/etc/myapp/** /*.yml    # find files in the directory or subdirectories

See more about the possible matchings at alinex-fs.

Web Services

Like using files you may also always use a web service to get the configuration. But keep in mind that your system may not start if the web service is down.

It is as easy as using files:

CoffeeScript Code
config.pushOrigin uri: "http://echo.jsontest.com/key/value/one/two" path: 'echo'

This will result in the following configuration (after loaded via init()).

CoffeeScript Code
echo: one: 'two' key: 'value'

Support for webservice formats like XML-RPC, JSON-RPC and SOAP may be integrated later. Also the support of possibilities to specify the concrete request may be extended on demand.

Here you won’t have a search possibility.

Parsing data

The data loaded from the given URI will be parsed if it is a string. You may set one of the following parsers in parser to use:

  • yaml
  • json
  • xml
  • ini
  • properties
  • coffee
  • javascript

But if you don’t specify it, it will be auto detected based on the file extension or the contents itself. See more info about each type atalinex-format.

Combine contents

Use the filter path to only use a subset of the loaded structure and the path to specify where it belongs to.

filter: 'test'
path: 'database/test'

This will only use the test settings from the loaded data and put them into data.database.test.

If multiple files are found (maybe through multiple origins) their contents will be merged together in the order they are specified in the origin tree list. This means that the later one will overwrite the earlier one if they have values for the same element.

Order

The origin structure is a tree list which will be processed top down. This means that you can add new origin objects at the top to use them as defaults or at the end of the list to make this the highest priority.

In case of registering applications using register() they will add a sublist with their search paths instead of an single entry. See more about this in the description below.

Extend Origin List

To maintain the order you can add at the front using unshiftOrigin() or at the end using pushOrigin().

pushOrigin(conf)

Add a new element to the origin list.

Usage:pushOrigin(conf)

Parameter
  • conf - Object origin specification (see above)

unshiftOrigin(conf)

Add a new element at the start of the origin list.

Usage:unshiftOrigin(conf)

Parameter
  • conf - Object origin specification (see above)

Registering Applications

An application have the possibility to search for their file based configuration on multiple locations out of the box:

  • var/src/config - defaults in the source code
  • var/local/config - local within the installed program
  • /etc/ - global for the application
  • ~/.app/config - user specific settings

As described above the last has the highest priority.

To support this in an easy way you may use the register method which if given an application name and the app directory will do everything for you.

CoffeeScript Code
config.register myapp, __dirname, uri: '*.yml'

Like you see, you may also add the attributes from the normal configuration like uri, filter and path.

You may also register a module. Therefore give null as application name and it will only add the first two paths based on the given directory.

If you won’t have your settings in the ‘config’ folder you may specify another one using folder: "..." as additional parameter.

Info

The general search path ‘alinex’ for all Alinex applications is already set after requiring config. This allows to always use the following folders if no other ones are given:

  • /etc/alinex
  • ~/.alinex

register(app, basedir, setup)

Usage:register(app, basedir, setup)

Parameter
  • app - String optional name of the application (in the filesystem)
  • basedir - String optional folder in which the application is installed
  • setup - Object origin specification (see above)

Setup Schema

The schema defines some validation and optimization rules which has to be processed before using the values. If the validation fails it will return a descriptive Error and don’t use the values.

setSchema()

CoffeeScript Code
config.setSchema '/', type: 'object' allowedKeys: true keys: name: type: 'string' job: type: 'string' , (err) -> # go on and load the data

To set a schema, give the root path for the schema and it’s values which describe the concrete data format. The real validation is done using the Validator. Therefore look at the description there for all the possibilities you have.

Usage:setSchema(path, schema, cb)

Parameter
  • path - String the configuration path to which the schema belongs to
  • schema - Object the schema definition foralinex-validator
  • cb - Function(Error) optional callback to be called after set and loaded objects validated with Error if validation failed
See also
-setSchemaSync

setSchemaSync

CoffeeScript Code
config.setSchemaSync '/', type: 'object' allowedKeys: true keys: name: type: 'string' job: type: 'string'

To set a schema, give the root path for the schema and it’s values which describe the concrete data format. The real validation is done using the Validator. Therefore look at the description there for all the possibilities you have.

Usage:setSchemaSync(path, schema)

Parameter
  • path - String the configuration path to which the schema belongs to
  • schema - Object the schema definition foralinex-validator
Throws
  • Error if it could not be validated
See also
-setSchema()

Initialize

After everything is setup you have to call the init() method to initialize it. This will:

  • search for the configurations
  • load them
  • parse them
  • combine all together
  • check using schema

After everything is done the given callback is called.

You may also call this method if you didn’t know if everything is initialized. It will check and return immediately if nothing to do.

init()

Usage:init(cb)

Parameter
  • cb - Function(Error) callback with Error on any problems
See also
-initSync

initSync

Throws
  • Error on any problems
See also
-init()

Reload

It is also possible to reread all data sources and change the registry to the new structure using thereload() method. This will do the same as the initalinit() already did.

reload()

Usage:reload(cb)

Parameter
  • cb - Function(Error) callback with Error on any problems
See also
-reloadSync -init()

reloadSync

Usage:reloadSync(cb)

Parameter
  • cb - Function(Error) callback with Error on any problems
See also
-reload() -initSync

Access

After everything is setup and loaded you may access the values or part of the value tree. You always get a reference for performance reasons. So don’t change it’s content.

CoffeeScript Code
conf = config.get()

Thats a simple call to get the complete data structure.

CoffeeScript Code
conf = config.get 'server' conf = config.get 'database/master/address'

Or give an path to get only a subpart of the configuration.

CoffeeScript Code
if config.get('server')? # value found

And at last you may check that a specific part is set.

get()

Usage:get(path)

Parameter
  • path - String to the element to read
Return
the value at this element position

Other Types

Beside configuration files you may also access templates or other user changeable files in the same manner using such an search path.

Therefore you have toregister() an app with a type:

CoffeeScript Code
config.register 'alinex', null, folder: 'template' type: 'template'

And later you may get all the possible files:

CoffeeScript Code
config.typeSearch 'template', (err, map) -> console.log err, map

You will get a map of files with

  • key: path relative from the URI
  • value: absolute file path

Web requests are not possible here.

typeSearch()

Search for files of the given type. The resulting map contains the path relative from the defined origin URI and the real path to access.

Usage:typeSearch(type, cb)

Parameter
  • type - String the name of this files
  • cb - Function(Error, Object) callback with the results map or an Error on any problems
See also
-typeSearchSync

typeSearchSync

Search for files of the given type. The resulting map contains the path relative from the defined origin URI and the real path to access.

Usage:typeSearchSync(type)

Parameter
  • type - String the name of this files
Return
Object the results map
Throws
  • Error on any problems
See also
-typeSearch()

Schema

originImportSchema

The schema may be used to validate possible origins before use. This is only done within the config module if debug is enabled.

Best Practice

I often use the pattern of giving my modules two functions called setup() and init(). The setup() is first called to set up the basics like configuring the configuration system.

CoffeeScript Code
# set the modules config paths and validation schema setup = util.function.once this, (cb) -> # set module search path config.register false, fspath.dirname __dirname # add schema for module's configuration config.setSchema '/exec', schema, cb

The call of util.function.once will look that this method is only run one time (see alinex-util).

Now you may add additional configuration paths…

CoffeeScript Code
# set the modules config paths, validation schema and initialize the configuration init = util.function.once this, (cb) -> debug "initialize" # set module search path @setup -> return cb err if err config.init cb

The init() method now makes the system ready to use and if not up to date or initialized will initialize the config system. The setup() is also called to make it possible to call in one step if no special configuration is needed.

Events

If you use the reload possibility, you may also add a function as listener which get informed if a specific part in the value changed.

To do so you can listen to value changes using the common on or once methods:

CoffeeScript Code
config = require 'alinex-config' ... config.on '/email', -> # what to do config.on '/app/title', -> # change the title in the view title = config.get '/app/title'

Your event listener will get called if the given value or the data below was changed. A reloading of the same value won’t count if the data keeps the same.