An open API service indexing awesome lists of open source software.

https://github.com/dbstratta/environment

🌳 Environment variable configuration for Node.js made easy.
https://github.com/dbstratta/environment

config configuration env environment nodejs typescript variables

Last synced: about 1 year ago
JSON representation

🌳 Environment variable configuration for Node.js made easy.

Awesome Lists containing this project

README

          

# environment

[![Azure Pipelines](https://img.shields.io/azure-devops/build/strattadb/0d9c480f-815f-404d-8d52-50af29a893e6/1/develop.svg?style=for-the-badge)](https://dev.azure.com/strattadb/environment/_build?definitionId=1)
[![npm](https://img.shields.io/npm/v/@strattadb/environment.svg?style=for-the-badge)](https://www.npmjs.com/package/@strattadb/environment)
[![Codecov](https://img.shields.io/codecov/c/github/dbstratta/environment/develop.svg?style=for-the-badge)](https://codecov.io/gh/dbstratta/environment)
[![David](https://img.shields.io/david/dbstratta/environment.svg?style=for-the-badge)](https://david-dm.org/dbstratta/environment)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge)](CONTRIBUTING.md)

Environment variable configuration for Node.js made easy.

## The problem

A lot of applications need to ensure that some environment variables are
set from the beginning, and checking if the value in `process.env` is `undefined`
every time is needed gets tedious very fast.

`environment` allows applications to ensure required env variables are set and are valid according
to _your_ definition of valid. See [how to use it](#usage).

## Table of Contents

- [environment](#environment)
- [The problem](#the-problem)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Usage](#usage)
- [Examples](#examples)
- [API](#api)
- [`makeEnv(schema: Schema, processEnv?: { [key: string]: string | undefined }): Env`](#makeenvschema-schema-processenv--key-string-string--undefined--env)
- [Parsers](#parsers)
- [`parsers.string(value: string): string`](#parsersstringvalue-string-string)
- [`parsers.boolean(value: string): boolean`](#parsersbooleanvalue-string-boolean)
- [`parsers.integer(value: string): number`](#parsersintegervalue-string-number)
- [`parsers.float(value: string): number`](#parsersfloatvalue-string-number)
- [`parsers.email(value: string): string`](#parsersemailvalue-string-string)
- [`parsers.url(value: string): string`](#parsersurlvalue-string-string)
- [`parsers.ipAddress(value: string): string`](#parsersipaddressvalue-string-string)
- [`parsers.port(value: string): number`](#parsersportvalue-string-number)
- [`parsers.whitelist(whitelistedValues: string[]): Parser`](#parserswhitelistwhitelistedvalues-string-parserstring)
- [`parsers.regex(pattern: Regex): Parser`](#parsersregexpattern-regex-parserstring)
- [`parsers.array({ parser: Parser, separator?: string }): Parser`](#parsersarrayt-parser-parsert-separator-string--parsert)
- [`parsers.positiveInteger(value: string): number`](#parserspositiveintegervalue-string-number)
- [`parsers.nonPositiveInteger(value: string): number`](#parsersnonpositiveintegervalue-string-number)
- [`parsers.negativeInteger(value: string): number`](#parsersnegativeintegervalue-string-number)
- [`parsers.nonNegativeInteger(value: string): number`](#parsersnonnegativeintegervalue-string-number)
- [Recipes](#recipes)
- [Making environment variables required](#making-environment-variables-required)
- [Specifying a default value for when the env variable is not required](#specifying-a-default-value-for-when-the-env-variable-is-not-required)
- [Providing a custom parser](#providing-a-custom-parser)
- [Usage with Dotenv](#usage-with-dotenv)
- [Providing your own processEnv object](#providing-your-own-processenv-object)
- [FAQ](#faq)
- [Where should I call `makeEnv` in my application?](#where-should-i-call-makeenv-in-my-application)
- [Does it support changing env variables dynamically?](#does-it-support-changing-env-variables-dynamically)
- [Can I use the `debug` module with `environment`?](#can-i-use-the-debug-module-with-environment)
- [Can I have more than one env object per application?](#can-i-have-more-than-one-env-object-per-application)
- [Node.js support](#nodejs-support)
- [Contributing](#contributing)
- [Maintainers](#maintainers)
- [Who's using environment](#whos-using-environment)
- [Related libraries](#related-libraries)
- [License](#license)

## Installation

With [Yarn](https://yarnpkg.com/):

```bash
yarn add @strattadb/environment
```

or with npm:

```bash
npm install @strattadb/environment
```

## Usage

An example `env.js` file:

```javascript
// env.js

import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
nodeEnv: {
parser: parsers.whitelist(['production', 'development', 'test']),
required: true,
envVarName: 'NODE_ENV',
},
port: {
parser: parsers.port,
required: false,
defaultValue: 4000,
envVarName: 'PORT',
},
});

export default env;
```

Now in a file:

```javascript
// otherFile.js

import env from './env';

console.log(env.nodeEnv); // development
console.log(typeof env.nodeEnv); // string

console.log(env.port); // 4000
console.log(typeof env.port); // number
```

## Examples

- [Simple HTTP server](examples/server)

## API

### `makeEnv(schema: Schema, processEnv?: { [key: string]: string | undefined }): Env`

Ensures required env variables are present and returns an env object.

Supports passing a processEnv object as the second argument.
If it's not passed, it uses `process.env`.
This object will be used to look up the environment variables.

- **Schema**:

- **\[key: string\]**: `object` - The `key` will be accessible
in the returning env object.
- **parser**: `function` - A function that takes a string and can return anything.
The return value will be accesible in `env[key]`.
If the argument is not valid, it should throw.
- **required**: `boolean` - Whether or not the env variable is required.
If the value `true` and the env variable is not set, it'll throw.
If the value is `false` it'll look for the env variable in `process.env`,
if isn't set, it'll use `defaultValue`.
- **defaultValue**: `any?` - Only valid if `required: false`.
This is the default value of the env variable if it's not set.
It won't be parsed or validated.
- **envVarName**: `string` - The name of the env variable to look up
(`process.env[envVarName]`).
- **description**: `string?` - Helper text describing the variable.

- **Env**:

- **\[key: string\]**: `any` - The keys are the same as the ones in the schema.

### Parsers

#### `parsers.string(value: string): string`

Trivial parser. It doesn't do any validation.

#### `parsers.boolean(value: string): boolean`

Ensures the value is a truthy or falsy value.

Truthy values: `'true'`, `'1'`, `'yes'`, `'on'`.

Falsy values: `'false'`, `'0'`, `'no'`, `'off'`.

#### `parsers.integer(value: string): number`

Ensures the value is an integer.

#### `parsers.float(value: string): number`

Ensures the value is a float.

#### `parsers.email(value: string): string`

Ensures the value is an email.

#### `parsers.url(value: string): string`

Ensures the value is a url.

#### `parsers.ipAddress(value: string): string`

Ensures the value is an IP address.

#### `parsers.port(value: string): number`

Ensures the value is a port.

#### `parsers.whitelist(whitelistedValues: string[]): Parser`

Takes a list of valid values and returns a parser that
ensures the value is in the whitelist.

Example:

```javascript
import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
color: {
parser: parsers.whitelilst(['red', 'blue', 'green']),
required: true,
envVarName: 'COLOR',
},
});
```

#### `parsers.regex(pattern: Regex): Parser`

Takes a regex and returns a parser that
ensures the value matches the pattern.

Example:

```javascript
import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
color: {
parser: parsers.regex(/^green$/),
required: true,
envVarName: 'COLOR',
},
});
```

#### `parsers.array({ parser: Parser, separator?: string }): Parser`

Takes a parser and returns a parser that parses a list of values.
The default value separator is `,`.

Example:

```javascript
import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
color: {
parser: parsers.array({ parser: parsers.integer }),
required: true,
envVarName: 'FAVORITE_NUMBERS',
},
});
```

#### `parsers.positiveInteger(value: string): number`

Ensures the value is a positive integer.

#### `parsers.nonPositiveInteger(value: string): number`

Ensures the value is a non-positive integer.

#### `parsers.negativeInteger(value: string): number`

Ensures the value is a negative integer.

#### `parsers.nonNegativeInteger(value: string): number`

Ensures the value is a non-negative integer.

## Recipes

### Making environment variables required

If `required` is `true` and the environment variable isn't set,
it'll throw:

```javascript
// env.js

import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
notSet: {
parser: parsers.string,
required: true,
envVarName: 'NOT_SET',
},
});
```

```bash
node env.js

EnvironmentVariableError: NOT_SET is required but is not set
at ...
...
```

### Specifying a default value for when the env variable is not required

If the env variable is not required you must specify a default value:

```javascript
import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
port: {
parser: parsers.port,
required: false,
defaultValue: 4000,
envVarName: 'PORT',
},
});

console.log(env.port); // 4000
```

### Providing a custom parser

A parser function must take a string value and can return anything.
The value you return is what you'll get in the env object.
If the value is not valid you should throw an error:

```javascript
import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv({
someValue: {
parser: (value) => {
if (value === 'forbiddenValue') {
throw new Error('value is forbidden');
}

return value;
},
required: true,
envVarName: 'SOME_VALUE',
},
});
```

### Usage with [Dotenv](https://github.com/motdotla/dotenv)

A common pattern is to load the env variables from a file using dotenv
and then ensuring that the required variables are actually present:

```javascript
const dotenv = require('dotenv');

dotenv.config(); // Loads env variables from `.env` file to `process.env`.

const { makeEnv, parsers } = require('@strattadb/environment');

const env = makeEnv({
secretToken: {
parser: parsers.string,
required: true,
envVarName: 'SECRET_TOKEN',
},
});
```

### Providing your own processEnv object

By default, `makeEnv` uses `process.env` to look up and get environment variables,
but you can pass you own processEnv object as the second argument that will
be used instead of `process.env`:

```javascript
import { makeEnv, parsers } from '@strattadb/environment';

const env = makeEnv(
{
hello: {
parser: parsers.string,
required: true,
envVarName: 'HELLO',
},
},
{
HELLO: 'WORLD',
},
);
```

## FAQ

### Where should I call `makeEnv` in my application?

The best place to create the env object is very early
in your application startup.
Everything before you call `makeEnv` with your schema will
not be guaranteed to have your required env variables.

### Does it support changing env variables dynamically?

No, when you create an env object it will read the value of
`process.env` at that time. After that, if anything makes
changes to `process.env`, it will not be reflected in the
env object.

### Can I use the [`debug`](https://github.com/visionmedia/debug) module with `environment`?

Yes! Set `DEBUG=environment`.

### Can I have more than one env object per application?

Yes! You can have as many env objects as you want!

## Node.js support

Node.js version 12 or higher. Every version of this library
is tested in Node.js 12, 14 and 16.

## Contributing

PRs, feature requests, bug reports, and any kind of contributions are welcome!
See [CONTRIBUTING.md](CONTRIBUTING.md).

## Maintainers

- [Diego Stratta](https://github.com/strattadb)

## Who's using environment

- [origen](https://github.com/origen-chat/api)

## Related libraries

- [Convict](https://github.com/mozilla/node-convict)
- [Envalid](https://github.com/af/envalid)
- [require-environment-variables](https://github.com/bjoshuanoah/require-environment-variables)
- [Dotenv](https://github.com/motdotla/dotenv)

## License

[MIT](LICENSE)