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 filehttp://
orhttps://
=> 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.
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 installedsetup
-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 toschema
-Object
the schema definition foralinex-validatorcb
-Function(Error)
optional callback to be called after set and loaded objects validated withError
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 toschema
-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 withError
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 withError
on any problems
- See also
- -
reloadSync
-init()
reloadSync
Usage:
reloadSync(cb)
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 filescb
-Function(Error, Object)
callback with the results map or anError
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.