node-config multiple configuration files - node.js

I am looking at this https://github.com/lorenwest/node-config, and it seems to do everything I need. However I am wondering if it's possible to specify multiple config files based on their categories.
Is this possible to do this?
./config
default-aws.json or aws-default.json
production-aws.json or aws-production.json
db-default.json
db-production.json
etc..
so the config files can be smaller? I know we could make a giant config that has all of those required in different sections. eg
{
"aws": {
"kinesis": "my-stream"
....
},
"db": {
"host": "my-host"
...
}
}
Anyone has any ideas if this is doable using node-config or different library that works similar to node-config?
Thanks & regards
Tin

The short answer is NO. node-config doesn't support this (As #Mark's response).
The simplest way to do this using node-config is to use JavaScript as config files (https://github.com/lorenwest/node-config/wiki/Configuration-Files#javascript-module---js). This way you still get most of the benefits of using node-config. Then you can simply include other files inside them (https://github.com/lorenwest/node-config/wiki/Special-features-for-JavaScript-configuration-files#including-other-files)
Note that it would be a bit harder to use the multiple config files and overrides for the inner files.
A slightly more complex implementation can use the utility class in config which actually allows you to directly read a specific folder using the same patterns that node-config uses internally (https://github.com/lorenwest/node-config/wiki/Using-Config-Utilities#loadfileconfigsdirectory).
In that case you would probably want to combine all the files to a single config by setting them on the config object before the first call to get (https://github.com/lorenwest/node-config/wiki/Configuring-from-an-External-Source).

I'm a maintainer of node-config. The next version will support a feature to declare multiple NODE_ENV values, separated by a comma.
So if you were doing development in the cloud, you could declare a "development" environment followed by a "cloud" environment.
First the development config would be loaded, followed by the "cloud" config.
The related pull request is #486.

I use nconf. It lets you read multiple configuration files into the same object. Here is an example:
var nconf = require('nconf');
//read the config files; first parameter is a required key
nconf.file('aws', {file: 'default-aws.json'});
nconf.file('db', {file: 'db-default.json'});
console.log(nconf.get('aws:kinesis'));
console.log(nconf.get('db:host'));
default-aws.json:
{
"aws": {
"kinesis": "my-stream"
}
}
db-default.json:
{
"db": {
"host": "my-host"
}
}

Related

RequireJS Map Configuration of Multiple files

I have some files, like,
test/test1,
test/test2,
test/test3
and i want to rename there path to
newtest/test1,
newtest/test2,
newtest/test3
so that if we try to require the above file, then it will point to new path.
In require, one to one mapping is present, but not sure, if something like this is achievable,
require.map = {
"test/*": "newtest/*",
}
Any help :)
The map configuration option supports mapping module prefixes. Here's an example:
require.config({
map: {
"*": {
"foo": "bar"
}
}
});
define("bar/x", function () {
return "bar/x";
})
require(["foo/x"], console.log);
The last require call that tries to load foo/x will load bar/x.
This is as good as it gets for pattern matching with map. RequireJS does not support putting arbitrary patterns in there. Using "test/*": "newtest/*" would not work. The "*" I used in map is not a pattern. It is a hardcoded value that means "in all modules", and happens to look like a glob pattern. So the map above means "in all modules, when foo is required, load bar instead".
I wonder if you really need map. You can probably just use paths. Quoting from map documentation
This sort of capability is really important for larger projects which
may have two sets of modules that need to use two different versions
of 'foo', but they still need to cooperate with each other.
Also see paths documentation
Using the above sample config, "some/module"'s script tag will be
src="/another/path/some/v1.0/module.js".
Here is how paths can be used to map the directory from test to newtest for your example
paths: {
"test": "newtest"
}

Botbuilder how to use default locale strings in case namespace hasn't defined it

I am using the botbuilder framework. I have defined several namespaces for the dialogs I have created, such as help or default. For all of these I have also created json files in my locale/en/ directory, and all is well.
However, I have a few sentences that are very common, and I don't feel like copying those over to each of the individual namespaces. I have tried using index.json as a 'fallback' in case the namespace file doesn't define the string. But it doesn't work for me. Contrary to what the documentation seems to suggest.
/locale
/en
/help.json
/default.json
/index.json <-- Doesn't work
/dialogs
/help.js
/default.js
bot.js
Say I have the following library in help.js, that :
lib = new builder.Library('help')
lib.dialog('/', (session) => {
session.send('custom_cancel')
}
module.exports = lib
The library is used in bot.js:
bot.library(require('./dialogs/help'))
And index.json has this content:
{
"custom_cancel": "My custom cancel"
}
Whereas help.json is empty:
{}
Because help.json does not have custom_cancel, the bot will actually send custom_cancel as the string.
Again. I can copy paste the strings to both locations and there is no more problem. But that seems like an ugly solution to me.
I have tried the more explicit version, which seems to help in more cases, but I am not fully convinced yet.
session.localizer.gettext(session.preferredLocale(), 'custom_cancel')
You can use the third argument for the namespace. It seems that '' will point to the index.json file.

Best way to define custom functions in loopback api

What is the best way to define custom functions in loopback api that can be used in models defined ?
For example a basic express application can have functions in helper folder on root directory, but doing same in loopback is not recommended and does not maintain loopback way.
Any help would be highly appreciated.
This is very well documented.
Custom logic can be placed in
boot scripts
middlewares
models:
remote methods
remote hooks
operation hooks
application-decoupled logic can very well be put in helper folders, separate folders at root level, etc. There is nothing wrong with modularizing your program this way, it is actually a good thing.
As mentioned by others, the Loopback documentation answers your question like this:
Adding logic to models - adding remote methods, remote hooks and operation hooks.
Defining boot scripts - writing scripts (in the /server/boot directory) that run when the application starts.
Defining middleware - adding custom middleware to the application .
That's a great answer if you have custom functions for a particular model, boot script, or middleware. And as Dharmendra Yadav said, mixins can be another option:
You can use mixins to perform different common actions on models such as observing changes using operation hooks and adding model attributes.
But what about code that simply doesn't fit into any of those categories?
I don't have experience with a lot of web frameworks, but one framework I have used is Grails, which is very opinionated and gives you a place for just about everything. And if your code doesn't fit into any of those categories, they give you a place for that too:
src/main/groovy - Supporting sources
So when I ran into this same problem in Loopback, I just created a src directory under server and that's where I put some helper classes that don't seem to fit anywhere else. And I include them as needed:
const HelperClass = require('../src/HelperClass');
HelperClass.helperFunction()...
Of course you can name the folder however you'd like: src, helpers, support, whatever. And then put it under common or server as appropriate.
The best way to define functions in loopback i found is to use mixins. Here is the sample way of doing so..
https://loopback.io/doc/en/lb3/Defining-mixins.html
You can inherit these defined mixins into your models through .json of your model with {mixins:yourmixin.js}, nice and easy.
Here's some sample code to get you headed in the right direction.
mynewmodel.js
http://domain/api/mynewmodel/myfunc.js
function myfunc(data, callback) {
// ** Put your code here **
console.log('myfunc');
}
function remoteMethod(model) {
model.remoteMethod(
'myfunc',
{
http: { verb: 'post' },
accepts: { arg: 'data', type: 'data' },
returns: [
{ arg: 'returndata', type: 'data' }
]
}
)
}
UPDATE
Generally your js files go in common/models

Writing ENV variables to configure an npm module

I currently have a project in a loose ES6 module format and my database connection is hard coded. I am wanting to turn this into an npm module and am now facing the issue of how to best allow the end user to configure the code. My first attempt was to rewrite it as classes to be instantiated but it is making the use of the code more convoluted than before so am looking at alternatives. I am exploring my configuration options. It looks like writing to the process env would be the way but I am pondering potential issues, no-nos and other options I have not considered.
Is having the user write config to process env an acceptable method of configuring an npm module? It's a bit like a global write so am dealing with namespace considerations for one. I have also considered using package.json but that's not going to work for things like credentials. Likewise using an rc file is cumbersome. I have not found any docs on the proper methodology if any.
process.env['MY_COOL_MODULE_DB'] = ...
There are basically 5ish options as I see it:
hardcode - not an option
create a configured scope such as classes - what I have now and bleh
use a config such as node-config - not really a user friendly option for npm
store as globals/env. As suggested in comment I can wrap that process in an exported function and thereby ensure that I have a complex non collisive namespace while abstracting that from end user
Ask user to create some .rc file - I would if I was big time like AWS but not in this case.
I mention this npm use case but this really applies to the general challenge of configuring code that is exported as functions. I have use cases for classes but when the only need is creating a configured scope at the expense (in my case) of more complex code I am not sure its worth it.
Update I realize this is a bit of a discussion question but it's helped me wrap my brain around options. I think something like this:
// options.js
let options = {}
export function setOptions(o) { options = o }
export function getOptions(o) { return options }
Then have the user call setOptions() and call this getOptions internally. I realize that since Node requires the module just once that my options object will be kept configured as I pass it around.
NPM modules should IMO be agnostic as to where configuration is stored. That should be left up to the developer, and they may pick their favorite method (env vars, rc files, JSON files, whatever).
The configuration can be passed to your module in various ways. A common way is to export a function that takes an options object:
export default options => {
let db = database.connect(options.database);
...
}
From there, it really depends on what exactly your module provides. If it's just a bunch of loosely coupled functions, you can just return an object:
export default options => {
let db = database.connect(options.database);
return {
getUsers() { return db.getUsers() }
}
}
If you want to allow multiple versions of that object to exist simultaneously, you can use classes:
class MyClass {
constructor(options) {
...
}
...
}
export default options => {
return new MyClass(options)
}
Or export the entire class itself.
If the number of configuration options is limited (say 3 or less), you can also allow them to be passed as separate arguments, instead of passing an object.

Intern: DRY Runners for multiple project in one workspace

While realizing that my project setup might be the root cause of my problem, here's what I'd like some help with (moving from another framework to Intern):
I've different (>20) projects in one dev workspace, so I've (>20) different directories with test code. I'd like a project to be testable on itself, but also would like to execute all suites together.
I am specifying to use RequireJS as an AMD loader and where my tests can be found per project (one for nodeJS, one for browsers) through a config file. PLUS I have one overall config file specifying all the files.
You can image there is quite the duplication, what would be a good approach to DRY this up?
Note: it would also be welcome to help to describe my problem better (more generic or less TLDR)!
Since Intern configuration files are just AMD modules you can use the normal dependency loading mechanism to load and combine configuration data from multiple files:
// in your “do everything” master configuration
define([
'projectA/tests/intern',
'projectB/tests/intern',
'projectC/tests/intern',
// …
], function () {
var configs = Array.prototype.slice.call(arguments, 0);
function getCombined(key) {
return Array.prototype.concat.apply([], configs.map(function (config) {
return config[key];
}));
}
return {
suites: getCombined('suites'),
functionalSuites: getCombined('functionalSuites'),
// …
};
});

Resources