Skip to content

Latest commit

 

History

History
485 lines (350 loc) · 14.8 KB

API.md

File metadata and controls

485 lines (350 loc) · 14.8 KB

API

A complete listing of the env-var API.

Structure

from(values, extraAccessors, logger)

This function is useful if you are not in a typical Node.js environment, want to set defaults, or for testing. It allows you to generate an env-var instance that reads from the given values instead of the default process.env Object.

const env = require('env-var').from({
  API_BASE_URL: 'https://my.api.com/'
})

// apiUrl will be 'https://my.api.com/'
const apiUrl = env.get('API_BASE_URL').asUrlString()

When calling env.from() you can also pass an optional parameter containing custom accessors that will be attached to any variables returned by that env-var instance. This feature is explained in the extraAccessors section of these docs.

Logging can be enabled by passing a logger function that matches the signature:

/**
 * Logs the provided string argument
 * @param {String} varname
 * @param {String} str
 */
function yourLoggerFn (varname, str) {
  // varname is the name of the variable being read, e.g "API_KEY"
  // str is the log message, e.g "verifying variable value is not empty"
}

get(varname)

This function has two behaviours:

  1. Passing a string argument will read that value from the environment
  2. If no argument is passed it will return the entire environment object

Examples:

const env = require('env-var')

// #1 - Read the requested variable and parse it to a positive integer
const limit = env.get('MAX_CONNECTIONS').asIntPositive()

// #2 - Returns the entire process.env object
const allVars = env.get()

variable

A variable is returned when env.get(varname) is called. It exposes the following functions to validate and access the underlying value, set a default, or set an example value:

example(string)

Allows a developer to provide an example of a valid value for the environment variable. If the variable is not set (and required() was called), or the variable is set incorrectly this will be included in error output to help developers diagnose the error.

For example:

const env = require('env-var')

const ADMIN_EMAIL = env.get('ADMIN_EMAIL')
  .required()
  .example('admin@example.com')
  .asString()

If ADMIN_EMAIL was not set this code would throw an error similar to that below to help a developer diagnose the issue:

env-var: "ADMIN_EMAIL" is a required variable, but it was not set. An example
of a valid value would be "admin@example.com"

default(defaultValue: string)

Allows a default value to be provided for use if the desired environment variable is not set in the program environment, i.e not present on process.env.

Example:

const env = require('env-var')

// Use POOL_SIZE if set, else use a value of 10
const POOL_SIZE = env.get('POOL_SIZE').default('10').asIntPositive()

required(isRequired = true)

Ensure the variable is set on process.env. If the variable is not set, or is set to an empty value, this function will cause an EnvVarError to be thrown when you attempt to read the value using asString or a similar function.

The required() check can be bypassed by passing false, i.e required(false)

Example:

const env = require('env-var')

// Get the value of NODE_ENV as a string. Could be undefined since we're
// not calling required() before asString()
const NODE_ENV = env.get('NODE_ENV').asString()

// Read PORT variable and ensure it's in a valid port range. If it's not in
// valid port ranges, not set, or empty an EnvVarError will be thrown
const PORT = env.get('PORT').required().asPortNumber()

// If mode is production then this is required
const SECRET = env.get('SECRET').required(NODE_ENV === 'production').asString()

convertFromBase64()

It's a common need to set an environment variable in base64 format. This function can be used to decode a base64 environment variable to UTF8.

For example if we run the script script below, using the command DB_PASSWORD= $(echo -n 'secret_password' | base64) node, we'd get the following results:

console.log(process.env.DB_PASSWORD) // prints "c2VjcmV0X3Bhc3N3b3Jk"

// dbpass will contain the converted value of "secret_password"
const dbpass = env.get('DB_PASSWORD').convertFromBase64().asString()

asArray([delimiter: string])

Reads an environment variable as a string, then splits it on each occurence of the specified delimiter. By default a comma is used as the delimiter. For example a var set to "1,2,3" would become ['1', '2', '3']. Example outputs for specific values are:

  • Reading MY_ARRAY='' results in []
  • Reading MY_ARRAY='1' results in ['1']
  • Reading MY_ARRAY='1,2,3' results in ['1', '2', '3']

asBool()

Attempt to parse the variable to a Boolean. Throws an exception if parsing fails. The var must be set to either "true", "false" (upper or lowercase), 0 or 1 to succeed.

asBoolStrict()

Attempt to parse the variable to a Boolean. Throws an exception if parsing fails. The var must be set to either "true" or "false" (upper or lowercase) to succeed.

asEnum(validValues: string[])

Converts the value to a string, and matches against the list of valid values. If the value is not valid, an error will be raised describing valid input.

asFloat()

Attempt to parse the variable to a float. Throws an exception if parsing fails.

asFloatNegative()

Performs the same task as asFloat(), but also verifies that the number is negative (less than or equal to zero).

asFloatPositive()

Performs the same task as asFloat(), but also verifies that the number is positive (greater than or equal to zero).

asInt()

Attempt to parse the variable to an integer. Throws an exception if parsing fails. This is a strict check, meaning that if the process.env value is "1.2", an exception will be raised rather than rounding up/down.

asIntNegative()

Performs the same task as asInt(), but also verifies that the number is negative (less than or equal to zero).

asIntPositive()

Performs the same task as asInt(), but also verifies that the number is positive (greater than or equal to zero).

asJson()

Attempt to parse the variable to a JSON Object or Array. Throws an exception if parsing fails.

asJsonArray()

The same as asJson but verifies that the data is a JSON Array, e.g. [1,2].

asJsonObject()

The same as asJson but verifies that the data is a JSON Object, e.g. {a: 1}.

asPortNumber()

Converts the value of the environment variable to an integer and verifies it's within the valid port range of 0-65535. As a result well known ports are considered valid by this function.

asRegExp([flags: string])

Read in the variable and construct a RegExp instance using its value. An optional flags argument is supported. The string passed for flags is passed as the second argument to the RegExp constructor.

asString()

Return the variable value as a String. Throws an exception if value is not a String. It's highly unlikely that a variable will not be a String since all process.env entries you set in bash are Strings by default.

asUrlObject()

Verifies that the variable is a valid URL string using the same method as asUrlString(), but instead returns the resulting URL instance. It uses the WHATWG URL constructor.

asUrlString()

Verifies that the variable is a valid URL string and returns the validated string. The validation is performed by passing the URL string to the WHATWG URL constructor.

Note that URLs without paths will have a default path / appended when read, e.g. https://api.acme.org would become https://api.acme.org/. Always use URL safe utilities included in the Node.js URL module to create valid URL strings, instead of error prone string concatenation.

EnvVarError()

This is the error class used to represent errors raised by this module. Sample usage:

const env = require('env-var')
let value = null

try {
  // will throw if you have not set this variable
  value = env.get('MISSING_VARIABLE').required().asString()

  // if catch error is set, we'll end up throwing here instead
  throw new Error('some other error')
} catch (e) {
  if (e instanceof env.EnvVarError) {
    console.log('we got an env-var error', e)
  } else {
    console.log('we got some error that wasn\'t an env-var error', e)
  }
}

Examples

const env = require('env-var');

// Normally these would be set using "export VARNAME" or similar in bash
process.env.STRING = 'test';
process.env.INTEGER = '12';
process.env.BOOL = 'false';
process.env.JSON = '{"key":"value"}';
process.env.COMMA_ARRAY = '1,2,3';
process.env.DASH_ARRAY = '1-2-3';

// The entire process.env object
const allVars = env.get();

// Returns a string. Throws an exception if not set or empty
const stringVar = env.get('STRING').required().asString();

// Returns an int, undefined if not set, or throws if set to a non integer value
const intVar = env.get('INTEGER').asInt();

// Return a float, or 23.2 if not set
const floatVar = env.get('FLOAT').default('23.2').asFloat();

// Return a Boolean. Throws an exception if not set or parsing fails
const boolVar = env.get('BOOL').required().asBool();

// Returns a JSON Object, undefined if not set, or throws if set to invalid JSON
const jsonVar = env.get('JSON').asJson();

// Returns an array if defined, or undefined if not set
const commaArray = env.get('COMMA_ARRAY').asArray();

// Returns an array if defined, or undefined if not set
const commaArray = env.get('DASH_ARRAY').asArray('-');

// Returns the enum value if it's one of dev, test, or live
const enumVal = env.get('ENVIRONMENT').asEnum(['dev', 'test', 'live'])

accessors

A property that exposes the built-in accessors that this module uses to parse and validate values. These work similarly to the asString() and other accessors exposed on the variable type documented above, however they accept a String as their first argument, e.g:

const env = require('env-var')

// Validate that the string is JSON, and return the parsed result
const myJsonDirectAccessor = env.accessors.asJson(process.env.SOME_JSON)

const myJsonViaEnvVar = env.get('SOME_JSON').asJson()

All of the documented asX() accessors above are available. These are useful if you need to build a custom accessor using the extraAccessors functionality described below.

extraAccessors

When calling from() you can also pass an optional parameter containing additional accessors that will be attached to any variables gotten by that env-var instance.

Accessor functions must accept at least one argument:

  • {*} value: The value that the accessor should process.

Important: Do not assume that value is a string!

Example:

const { from } = require('env-var')

// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'

// Add an accessor named 'asEmail' that verifies that the value is a
// valid-looking email address.
const env = from(process.env, {
  asEmail: (value) => {
    const split = String(value).split('@')

    // Validating email addresses is hard.
    if (split.length !== 2) {
      throw new Error('must contain exactly one "@"')
    }

    return value
  }
})

// We specified 'asEmail' as the name for the accessor above, so now
// we can call `asEmail()` like any other accessor.
let validEmail = env.get('ADMIN').asEmail()

The accessor function may accept additional arguments if desired; these must be provided explicitly when the accessor is invoked.

For example, we can modify the asEmail() accessor from above so that it optionally verifies the domain of the email address:

const { from } = require('env-var')

// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'

// Add an accessor named 'asEmail' that verifies that the value is a
// valid-looking email address.
//
// Note that the accessor function also accepts an optional second
// parameter `requiredDomain` which can be provided when the accessor is
// invoked (see below).
const env = from(process.env, {
  asEmail: (value, requiredDomain) => {
    const split = String(value).split('@')

    // Validating email addresses is hard.
    if (split.length !== 2) {
      throw new Error('must contain exactly one "@"')
    }

    if (requiredDomain && (split[1] !== requiredDomain)) {
      throw new Error(`must end with @${requiredDomain}`)
    }

    return value
  }
})

// We specified 'asEmail' as the name for the accessor above, so now
// we can call `asEmail()` like any other accessor.
//
// `env-var` will provide the first argument for the accessor function
// (`value`), but we declared a second argument `requiredDomain`, which
// we can provide when we invoke the accessor.

// Calling the accessor without additional parameters accepts an email
// address with any domain.
let validEmail = env.get('ADMIN').asEmail()

// If we specify a parameter, then the email address must end with the
// domain we specified.
let invalidEmail = env.get('ADMIN').asEmail('github.com')

This feature is also available for Typescript users. The ExtensionFn type is exposed to help in the creation of these new accessors.

import { from, ExtensionFn, EnvVarError } from 'env-var'

// Environment variable that we will use for this example:
process.env.ADMIN = 'admin@example.com'

const asEmail: ExtensionFn<string> = (value) => {
  const split = String(value).split('@')

  // Validating email addresses is hard.
  if (split.length !== 2) {
    throw new Error('must contain exactly one "@"')
  }

  return value
}

const env = from(process.env, {
  asEmail
})

// Returns the email string if it's valid, otherwise it will throw
env.get('ADMIN').asEmail()

You can view an example of composing built-in accessors made available by env.accessors in an extra accessor at examples/custom-accessor.js.