Getting Configuration Into a Node Module

logo

If you’re building a web service or web application, chances are you have a means of “configuring” your application. Usually, that means reading key/value pairs from somewhere (disc, service, db) and using those pairs to drive the behavior of your application. An example of this is a configuration value that tells your application which port to bind to.

In Node, we have modules. Oftentimes, modules will need some sort of configuration to be useful. This post is intended to explore the ways that we can get a configuration object into a node module.

Use a require statement

A straightforward way to get configuration into your module is using a require statement. Something like this:

const config = require('./config')

Pro

  • Straightforward. Within the module, you can see where configuration is coming from.

Con

  • Testing may require a utility like proxyquire. I’m not a fan of these tools, I think they violate the “principle of least surprise”.
  • You lose the context of a given transaction. Sometimes you want to tack things like request-id onto your configuration object. You cannot do that using this method.

Inject as a parameter

You can inject configuration into a Node module by using function parameters. Something like this:

function example(config, username) {...}

module.exports = example

Pro

  • Mocks, stubs and spies are possible with this approach.
  • The function argument is clearly stated during function invocation.

Con

  • Can lead to excessive function parameters (I tend to not like any more than 3).

Inject as a single parameter by using a parameter object

This is a variant of the previous approach, Inject as a parameter. You can collapse your function parameters into a single object, and place your configuration on that object. Something like this:

function example({config, username}) {...}

module.exports = example

Pro

Con

  • This is still susceptible to excessive function parameters – tucking them into an object doesn’t correct the fact that your excessive function parameters might be a smell telling you that your function is violating the Single Responsibility Principle.

Partially apply configuration at require time

You can also use partial application to get configuration into your Node module. Something like this:

function example(config){
  return function(username){...}
}

module.exports = example

Pro

  • Function takes less parameters.

Con

  • The partial application usually happens near a require for the module, and sometimes there is distance between that require and the invocation of the final function.

Which one should I use?

Like all things, context matters. I typically shy away from using the “Use a require statement” approach, in practice the coupling is too direct for my taste. I’ve been trying the “Partially apply configuration at require time” approach with some success lately, but I don’t like that I often am refering to the top of a module in order to see where the configuration is coming from.

What do you think? Tweet at me.


492 Words

2018-07-01 06:05 +0000