Search code examples
javascriptnode.jsjavascript-objectshapi.jswinston

Setting default value of filtered object in HapiJS Confidence configuration object


I'm using the Confidence library (in the HapiJS suite) for configuration management in my project (This config file specifically is for WinstonJS transports), and I was wondering if it was possible to set a default value for a single item in a filtered object. I'm not sure I'm explaining this right, I'm not positive what the correct terminology is, so heres an example:

I have a section of my configuration setup like so currently:

module.exports =  {
    $filter: 'env',
    development: {
        level: {
            console: 'debug',
            file: 'debug'
        },
        path: 'app-core.log'
    },
    staging: {
        level: {
            console: 'warn',
            file: 'warn'
        },
        path: 'app-core.log'
    },
    production: {
        level: {
            console: 'error',
            file: 'error'
        },
        path: 'prod-app-core.log'
    }
}

But since the path should be the same for all of the env items, with the exception of production, I was hoping that I could set the default value for just the path value. Something like this:

module.exports =  {
    $filter: 'env',
    development: {
        level: {
            console: 'debug',
            file: 'debug'
        }
    },
    staging: {
        level: {
            console: 'warn',
            file: 'warn'
        }
    },
    production: {
        level: {
            console: 'error',
            file: 'error'
        },
        path: 'prod-app-core.log'
    },
    $default: {
        path: 'app-core.log'
    }
}

Obviously, that doesn't work, but I hope it illustrates what I'm trying to accomplish. I can't find a way to set default values for single config items within objects, if I apply a filter (say staging), then it takes the entire staging object, and doesn't even look at the $default object.

Thanks!

P.S. While I would like to know if this is possible via Confidence (for other purposes), if it turns out that this isn't possible, then is there a way to set the default path for WinstonJS file transports?


Solution

  • I think you're looking for $base. See the shared values section in the docs:

    If you have values that you would like to share between various configuration objects without duplicating them for each option, you can create a $base object.

    Here's how it's used with your example:

    const Confidence = require('confidence');
    
    const document = {
        $filter: 'env',
        $base: {
            path: 'app-core.log'
        },
        development: {
            level: {
                console: 'debug',
                file: 'debug'
            }
        },
        staging: {
            level: {
                console: 'warn',
                file: 'warn'
            }
        },
        production: {
            level: {
                console: 'error',
                file: 'error'
            },
            path: 'prod-app-core.log'
        }
    };
    
    const store = new Confidence.Store(document);
    
    console.log(store.get('/', { env: 'production' }));
    console.log(store.get('/', { env: 'development' }));
    

    Console output:

    { path: 'prod-app-core.log',
      level: { console: 'error', file: 'error' } }
    { path: 'app-core.log',
      level: { console: 'debug', file: 'debug' } }
    

    So what's $default for then?

    $default is used to define an object that should be used when the env value doesn't have a corresponding key in the document. Without a $default, you'd just get undefined for that path:

    const document = {
        $filter: 'env',
        $base: {
            path: 'app-core.log'
        },
        $default: {
            level: {
                console: 'something-else',
                file: 'something-else'
            }
        },
        development: {
            level: {
                console: 'debug',
                file: 'debug'
            }
        },
        staging: {
            level: {
                console: 'warn',
                file: 'warn'
            }
        },
        production: {
            level: {
                console: 'error',
                file: 'error'
            },
            path: 'prod-app-core.log'
        }
    };
    
    const store = new Confidence.Store(document);
    
    console.log(store.get('/', { env: 'dunno' }));
    

    Console output:

    { path: 'app-core.log',
      level: { console: 'something-else', file: 'something-else' } }
    

    Anything defined at $default level or a specific matching filter value will take precedence over the value defined at $base.