node-convict icon indicating copy to clipboard operation
node-convict copied to clipboard

env should accept an array

Open sullivanpt opened this issue 9 years ago • 7 comments
trafficstars

Production deployment services like heroku typically use a diverse set of "standard" providers, each with a similar format but their own environment variable. It'd be nice to support these "out of the box". So something like:

mongoUri: {
    doc: "Mongo DB configuration string.",
    format: "uri",
    default: 'mongodb://localhost/fullstack',
    env: ["MONGOLAB_URI", "MONGOHQ_URL"]
  }

sullivanpt avatar Mar 01 '16 14:03 sullivanpt

I think there's some real merit to this idea, but let's play "see if we can sink it" first. If you can answer these, then I think your boat will float.

Hypothetically, what do you see happening if:

  • [ ] both env vars are found?
    • [ ] and they don't match?
  • [ ] Could users still accomplish creating custom validations for these values without complicating the convict api?
    • [ ] How do the decisions/outcomes from the "both found" scenario get passed into custom validators... or do they even get passed to custom validators?
  • [ ] Would there be situations where dynamically constructing the schema wouldn't work? (see below)

The other consideration to be made here, is that the simplicity of convict results in a clean separation of logic from the purpose of convict's schema. I think this introduces un-needed decision making into convicts core api.

A Better Option? Use convict.load to build your schema dynamically

Keeping in mind that convict accepts a schema object, you could achieve this same functionality through a function, instead of an object literal, and use convict.load at runtime to build the schema so that it uses the env value most appropriate for the platform your app is hosted on.

LongLiveCHIEF avatar Apr 27 '16 14:04 LongLiveCHIEF

I fail to see how using convict.load to dynamically build a schema would be more readable than a static declaration. However, I don't actually use convict in any of my projects. Feel free to close this change request if you think it is out of scope from the project goals.

sullivanpt avatar Apr 27 '16 15:04 sullivanpt

I'm not a maintainer, but I think the idea could be useful, and I could see myself taking the time to code it up and submit a PR. The task items above are the considerations that would have to be made (as far as I see them anyways) in order to make the code function properly.

Whether or not it's in scope... well, maybe it isn't now but maybe it should be... if we can answer the challenges I mentioned above. I'm sorry if I came across as condescending. My intentions were to only to discuss with you and perhaps prove that there is a gap, and and also that it's a gap we can/should fill.

LongLiveCHIEF avatar Apr 27 '16 17:04 LongLiveCHIEF

This would also be a common need for picking up env vars such as proxies, which are often formatted differently between operating systems and platforms.

I just went down two roads, and couldn't come up with an answer:

Coercion

I thought perhaps we could coerce the values, but the coercion operates on the value of the environment variable by first identifying it from the schema provided... meaning it's already too late.

Dynamic creation of schema node via convict.load();

I actually have a use case right now for this as well, only instead of deciphering between two possible environment variable values, I need to decipher whether or not the value exists... but I'm running into a bit of a chicken/egg here as well.

Will share some code in a bit after I work through this to be sure.

LongLiveCHIEF avatar Apr 27 '16 17:04 LongLiveCHIEF

Here's a great situation where having an array would be useful.

I have two config parameters: cookie.name (process.env.COOKIE_NAME) and cookie.signing_name (process.env.SIGNING_COOKIE_NAME).

The behavior I want to capture is when process.env.COOKIE_NAME is provided, and process.env.SIGNING_COOKIE_NAME is not, I want to set cookie.signing_name to process.env.COOKIE_NAME.

Without adding logic after the initial convict({...}), I can't encapsulate that behavior.

wyattjoh avatar Nov 23 '17 21:11 wyattjoh

Similar to #125


  • [ ] both env vars are found?

Priority order (first find).

  • [ ] and they don't match?

Default value or error like actual

  • [ ] Could users still accomplish creating custom validations for these values without complicating the convict api?
    • [ ] How do the decisions/outcomes from the "both found" scenario get passed into custom validators... or do they even get passed to custom validators?

Priority order (first find), and validor check the first value found (without try the second env variable). For more -> CustomGetter #313

I think we should improve the env getter to get the first value found. If someone want more, he can make a customGetter.

A-312 avatar Dec 07 '19 08:12 A-312

You can do that with custom getter (next update, 6.0.0) :

convict.addGetter('env', function(envs, schema, stopPropagation) {
  if (!Array.isArray(envs))
    envs = [ envs ];

  for (let i = 0; i < envs.length; i++) {
    let value = schema._cvtCoerce(this.getEnv()[envs[i]]);
    if (typeof value !== 'undefined')
      return value;
  }
  // here will return undefined
}, false, true);

A-312 avatar Jan 06 '20 23:01 A-312