Configuration
About configuration
There are times when you need to avoid hard coding value in application because you need to change it without having to rebuild application binary. For example, you need to be able to store database credential in configuration rather than hard coding, so you can change it easily.
Fano Framework provides IAppConfiguration
interface for that purpose.
IAppConfiguration
IAppConfiguration
interface provides several methods,
getString()
accepts name and returns string value.getInt()
accepts name returns integer value.getBool()
accepts name returns boolean value.getFloat()
accepts name returns double value.has()
test if name is exists in configuration.
Built-in IAppConfiguration implementation
Fano Framework provides TJsonFileConfig
, TIniFileConfig
, TEnvConfig
class which loads configuration data from JSON, INI file and environment variables respectively.
Fano Framework also provides TCompositeConfig
and TNullConfig
class. First one is IAppConfiguration
implementation with capability to combine twoIAppConfiguration
instance and latter is null class implements IAppConfiguration
interface.
Load config from JSON
var config : IAppConfiguration;
...
config := TJsonFileConfig.create(
getCurrentDir() + '/config/config.json'
);
Load config from INI
var config : IAppConfiguration;
...
config := TIniFileConfig.create(
getCurrentDir() + '/config/config.ini',
'fano'
);
Last parameter is name of default section to use. Read INI file configuration section in this document for more information.
Load configuration from environment variables
var config : IAppConfiguration;
...
config := TEnvConfig.create();
Combine multiple configurations as one
TCompositeConfig
allows you to use multiple configurations. In following setup,
if configuration not found in environment variables, then it will try to find it in
config.json.
var config : IAppConfiguration;
...
config := TCompositeConfig.create(
TEnvConfig.create(),
TJsonFileConfig.create(
getCurrentDir() + '/config/config.json'
)
);
Register config instance to dependency container
To be able to use TJsonFileConfig
, TIniFileConfig
, TEnvConfig
, TCompositeConfig
and TNullConfig
class with dependency container, Fano Framework provides TJsonFileConfigFactory
, TIniFileConfigFactory
, TEnvConfigFactory
, TCompositeConfigFactory
and TNullConfigFactory
class which enables you to register above classes in container.
Register JSON config
container.add(
'config',
TJsonFileConfigFactory.create(
getCurrentDir() + '/config/config.json'
)
);
Register INI config
container.add(
'config',
TIniFileConfigFactory.create(
getCurrentDir() + '/config/config.ini'
)
);
Register environment variable config
container.add(
'config',
TEnvConfigFactory.create()
);
Register composite configurations
container.add(
'config',
TCompositeConfigFactory.create(
TNullConfigFactory.create(),
TJsonFileConfigFactory.create(getCurrentDir() + '/config/config.json')
)
);
Retrieve configuration instance from dependency container
To get configuration instance
var config : IAppConfiguration;
...
config := container.get('config') as IAppConfiguration;
or with array-like syntax
config := container['config'] as IAppConfiguration;
Read configuration data
Suppose you have JSON file with content as follows
{
"appName" : "MyApp",
"baseUrl" : "http://myapp.fano",
"session" : {
"name" : "fano_sess",
"dir" : "storages/sessions/"
},
"cookie" : {
"domain" : "myapp.fano",
"maxAge" : 3600
}
}
To get baseUrl
value,
var baseUrl : string;
...
baseUrl := config.getString('baseUrl');
To get dir
value,
var sessionDir : integer;
...
sessionDir := config.getString('session.dir');
To get maxAge
value,
var cookieMaxAge : integer;
...
cookieMaxAge := config.getInt('cookie.maxAge');
getString()
, getInt()
, getBool()
and getFloat()
methods accept second parameter
if you want to use different value when key does not exist.
baseUrl := config.getString('baseUrl', 'https://example.com');
If key baseUrl
is not found, it returns second parameter value.
INI file configuration
TIniFileConfig
is thin wrapper of Free Pascal TIniFile
. TIniFile
cannot read data from INI file that has no section. Your INI file must contain at least one section which serve as default section. The last parameter of TIniFileConfig
’s constructor expect name of default section. If you use TIniFileConfigFactory
, by default it uses fano
as default section if not specified. You can specify default section by calling setDefaultSection()
method as shown in following code.
container.add(
'config',
TIniFileConfigFactory.create(
getCurrentDir() + '/config/config.ini'
).setDefaultSection('hello')
);
Consider reading cookie.maxAge
configuration in code example above. It will read maxAge
from cookie
section.
[cookie]
maxAge=3600
However, because nested section are not allowed in INI file, you can only read one section. For example,
nestedData := config.getInt('fano.data.nested');
will read data from
[fano]
data.nested=test
Setting up application configuration with Fano CLI
When creating new project, you can use --config
parameter to setup application configuration.
Read Setup application configuration when creating project for more information.
You can also manually setting application configuration by overriding buildAppConfig()
method of TBasicAppServiceProvider
or TDaemonAppServiceProvider
class as shown in following code sample.
TAppServiceProvider = class(TDaemonAppServiceProvider)
protected
function buildAppConfig(
const container : IDependencyContainer
) : IAppConfiguration; override;
...
end;
...
function TAppServiceProvider.buildAppConfig(
const container : IDependencyContainer
) : IAppConfiguration;
begin
container.add(
'config',
TIniFileConfigFactory.create(
getCurrentDir() + '/config/config.ini'
)
);
result := container['config'] as IAppConfiguration;
end;