0 purchases
configuration service
Enables applications to make effective use of JSON configuration files.
Especially useful for backend services or CLI tools written in Dart but can
also be used with Flutter.
Features #
Type-safe processing of JSON configuration files
No need for code generation
Handles optional and required values
Can use defaults if values are missing
Supports environment variables (great to inject secrets)
Getting started #
Assume a configuration file config.json with the following contents:
{
"enable_graphql_playground": true,
"enable_introspection": true,
"enable_schema_download": true
}
copied to clipboard
To load such a configuration file in your application, create a class
MyConfigurationService that extends ConfigurationService and defines
typed properties for every configuration value you want to support:
class MyConfigurationService extends ConfigurationService {
// ConfigurationValue<bool> defines a boolean value. You can use bool,
// int, String, List<> as well as your own complex types (more below).
final enableGraphQLPlayground = ConfigurationValue<bool>(
// name of the value in the configuration file
name: "enable_graphql_playground",
// optionally specify a default that will be used the value doesn't exist in the configuration file
defaultValue: const Optional(false),
);
final enableIntrospection = ConfigurationValue<bool>(
name: "enable_introspection",
// Values can be marked as required. This will throw an exception if the value is missing in the configuration file.
isRequired: true,
);
final enableSchemaDownload = ConfigurationValue<bool>(
name: "enable_schema_download",
defaultValue: const Optional(false),
);
MyConfigurationService() {
// register all configuration values so that they are picked up by the loader
register(enableGraphQLPlayground);
register(enableIntrospection);
register(enableSchemaDownload);
}
}
copied to clipboard
Load the configuration file with loadFromJson():
void main() async {
final configurationService = MyConfigurationService();
await configurationService.loadFromJson(filePath: 'config.json');
print(configurationService.enableIntrospection.value);
}
copied to clipboard
Usage #
Access a value from the configuration file #
Assume the following configuration file exists:
{ "test": true }
copied to clipboard
The following code will read it:
final configurationValue = ConfigurationValue<bool>(name: 'test');
final configurationService = ConfigurationService();
configurationService.register(configurationValue);
await configurationService.loadFromJson(filePath: 'config.json');
print(configurationValue.value); // "true"
copied to clipboard
Check if a value exists #
final configurationValue = ConfigurationValue<bool>(name: 'test');
final configurationService = ConfigurationService();
configurationService.register(configurationValue);
await configurationService.loadFromJson(filePath: 'config.json');
print(configurationValue.hasValue()); // "true" if value exists in config.json
copied to clipboard
Use defaults #
final configurationValue = ConfigurationValue<bool>(name: 'test', defaultValue = Optional(true));
final configurationService = ConfigurationService();
configurationService.register(configurationValue);
await configurationService.loadFromJson(filePath: 'config.json');
print(configurationValue.hasValue()); // "true" even if it doesn't exist in config.json
print(configurationValue.hasValue(ignoreDefaults: true)); // only "true" if it exists in config.json
copied to clipboard
Mark values as required #
final configurationValue = ConfigurationValue<bool>(name: 'test', isRequired: true);
final configurationService = ConfigurationService();
configurationService.register(configurationValue);
// will throw an exception if "test" can't be found in the file
await configurationService.loadFromJson(filePath: 'config.json');
print(configurationValue.value);
copied to clipboard
Allow overrides from environment variables #
Using allowEnvironmentOverrides gives precedence to values found in the environment.
Names of environment variables are determined by re-casing the configuration value's name
to CONSTANT_CASE.
Examples:
verify_token becomes VERIFY_TOKEN
auth.verify_token becomes AUTH_VERIFY_TOKEN
final configurationValue = ConfigurationValue<bool>(name: 'test', isRequired: true);
final configurationService = ConfigurationService();
configurationService.register(configurationValue);
await configurationService.loadFromJson(filePath: 'config.json', allowEnvironmentOverrides: true);
print(configurationValue.value); // value that was found in env variable TEST, otherwise value from config file
copied to clipboard
Using configuration file sections #
It is often desirable to partition a configuration file in section for better maintainability.
A hierarchy of configuration value can be specified by using the dot notation.
Assume the following configuration file:
{
"auth": {
"verify_token": true
}
}
copied to clipboard
The value can be accessed by specifying auth.verify_token as its name.
Using complex types #
configuration_service understands int, String and bool natively as well as
corresponding List types. To load custom complex types, specify a deserializer
when registering the type:
configurationService.register(authEntityIdFallback, deserializers: {
EntityIdFallbackConfig: EntityIdFallbackConfig.fromJson,
});
copied to clipboard
This allows loading arbitrarily structured data from the configuration file. Make sure
that the fromJson method uses correct json keys to access the values from the
configuration data.
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.