Code Monkey home page Code Monkey logo

env's Introduction

@adonisjs/env

Environment variables parser and validator used by the AdonisJS.

gh-workflow-image typescript-image npm-image license-image

Note: This package is framework agnostic and can also be used outside of AdonisJS.

The @adonisjs/env package encapsulates the workflow around loading, parsing, and validating environment variables.

Setup

Install the package from the npm packages registry as follows.

npm i @adonisjs/env

EnvLoader

The EnvLoader class is responsible for loading the environment variable files from the disk and returning their contents as a string.

import { EnvLoader } from '@adonisjs/env'

const lookupPath = new URL('./', import.meta.url)
const loader = new EnvLoader(lookupPath)

const envFiles = await loader.load()

The return value is an array of objects with following properties.

  • path: The path to the loaded dot-env file.
  • contents: The contents of the file.

Following is the list of loaded files. The array is ordered by the priority of the files. The first file has the highest priority and must override the variables from the last file.

Priority File name Environment Should I .gitignore it Notes
1st .env.[NODE_ENV].local Current environment Yes Loaded when NODE_ENV is set
2nd .env.local All Yes Loaded in all the environments except test or testing environments
3rd .env.[NODE_ENV] Current environment No Loaded when NODE_ENV is set
4th .env All Depends Loaded in all the environments. You should .gitignore it when storing secrets in this file

EnvParser

The EnvParser class is responsible for parsing the contents of the .env file(s) and converting them into an object.

import { EnvParser } from '@adonisjs/env'
const envParser = new EnvParser(`
  PORT=3000
  HOST=localhost
`)

console.log(await envParser.parse()) // { PORT: '3000', HOST: 'localhost' }

The return value of parser.parse is an object with key-value pair. The parser also has support for interpolation.

By default, the parser prefers existing process.env values when they exist. However, you can instruct the parser to ignore existing process.env files as follows.

new EnvParser(envContents, { ignoreProcessEnv: true })

Identifier

You can define an "identifier" to be used for interpolation. The identifier is a string that prefix the environment variable value and let you customize the value resolution.

import { readFile } from 'node:fs/promises'
import { EnvParser } from '@adonisjs/env'

EnvParser.identifier('file', (value) => {
  return readFile(value, 'utf-8')
})

const envParser = new EnvParser(`
  DB_PASSWORD=file:/run/secret/db_password
`)

console.log(await envParser.parse()) // { DB_PASSWORD: 'Value from file /run/secret/db_password' }

This can be useful when you are using secrets manager like Docker Secret, HashiCorp Vault, Google Secrets Manager and others to manage your secrets.

Validating environment variables

Once you have the parsed objects, you can optionally validate them against a pre-defined schema. We recommend validation for the following reasons.

  • Fail early if one or more environment variables are missing.
  • Cast values to specific data types.
  • Have type safety alongside runtime safety.
import { Env } from '@adonisjs/env'

const validator = Env.rules({
  PORT: Env.schema.number(),
  HOST: Env.schema.string({ format: 'host' })
})

The Env.schema is a reference to the @poppinss/validator-lite schema object. Make sure to go through the package README to view all the available methods and options.

The Env.rules method returns an instance of the validator to validate the environment variables. The return value is the validated object with type information inferred from the schema.

validator.validate(process.env)

Complete example

Following is a complete example of loading dot-env files and validating them in one go.

Note: Existing process.env variables have the top most priority over the variables defined in any of the files.

import { Env } from '@adonisjs/env'

const env = await Env.create(new URL('./', import.meta.url), {
  PORT: Env.schema.number(),
  HOST: Env.schema.string({ format: 'host' })
})

env.get('PORT') // is a number
env.get('HOST') // is a string
env.get('NODE_ENV') // is unknown, hence a string or undefined

Env editor

The Env editor can be used to edit dot-env files and persist changes on disk. Only the .env and .env.example files are updated (if exists).

import { EnvEditor } from '@adonisjs/env/editor'

const editor = await EnvEditor.create(new URL('./', import.meta.url))
editor.add('PORT', 3000)
editor.add('HOST', 'localhost')

// Write changes on disk
await editor.save()

You can also insert an empty value for the .env.example file by setting the last argument to true.

editor.add('SECRET_VARIABLE', 'secret-value', true)

This will add the following line to the .env.example file.

SECRET_VARIABLE=

Known Exceptions

E_INVALID_ENV_VARIABLES

The exception is raised during environment variables validation exception. The exception is raised with Validation failed for one or more environment variables message.

You can access the detailed error messages using the error.cause property.

try {
  validate(envValues)
} catch (error) {
  console.log(error.cause)
}

env's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar julien-r44 avatar mcsneaky avatar romainlanz avatar targos avatar thetutlage avatar varun-nambiar avatar xstoudi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

env's Issues

Environment variable's value can not contain dollar '$' sign as first character

Adding a dollar sign $ as the first character in your .env file breaks the process.
The only way I could find to bypass this was not to validate it inside env.ts file.

Package version

v3.0.9

Node.js and npm version

node v16.13.2 (npm v8.1.2)

Sample Code (to reproduce the issue)

SOME_ENV_VALUE=$tart_value_with_dollar_sign

A sample repo to reproduce the issue

TEST REPO

Include value of environment variable in error output

In my case, NODE_ENV was equal to "test" because the app was booted in test mode. I needed some time to find that out because my .env was correct (with "development") and the error did not include the actual value:

Exception: E_INVALID_ENV_VALUE: Value for environment variable "NODE_ENV" must be one of "development,production"

- Missing environment variable "DB_DATABASE" while creating a new app

Package version

6.8.0

Describe the bug

Hey everyone!

I'm not sure if this can be considered as an issue, but every time I try to create a new app, I get an error in my terminal saying that an environment variable is missing.

So, yeah, I just need to set the variable, but in my opinion, it can be confusing for a beginner.

The entire message :

EnvValidationException: Validation failed for one or more environment variables

  • Missing environment variable "DB_DATABASE"

at start/env.ts:14
9| |
10| */
11|
12| import { Env } from '@adonisjs/core/env'
13|
❯ 14| export default await Env.create(new URL('../', import.meta.url), {
15| NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
16| PORT: Env.schema.number(),
17| APP_KEY: Env.schema.string(),
18| HOST: Env.schema.string({ format: 'host' }),
19| LOG_LEVEL: Env.schema.string(),

⁃ EnvValidator
node_modules/@adonisjs/env/src/validator.ts:27
⁃ Function.rules
node_modules/@adonisjs/env/src/env.ts:83
⁃ Function.create
node_modules/@adonisjs/env/src/env.ts:53

Have a good day

Reproduction repo

No response

Report all environment failed validations at once

Currently, if multiple environment variables fail the validation, only the first one is reported. Then, after fixing it, one has to restart the server and be notified of the next failed validation, etc.

I think it would be more user-friendly to collect and report all env validation errors at once.

Support for other types like integer

Why this feature is required (specific use-cases will be appreciated)?

It would be nice to have simple way of parsing integer from env. For example having env variable COUNT=10
will give you string. Currently this is a bit too much work to parse to int because of need to handle undefined and boolean values to satisfy typescript

Have you tried any other work arounds?

parseInt(Env.get('COUNT', 60) as string) but it is just ignoring undefined which is destroying purpose of typescript

Undefined is not removed from types when passing a default value

Package version

v2.0.5

Node.js and npm version

Node.js 14, npm 6

Sample Code (to reproduce the issue)

// in env.ts
import Env from '@ioc:Adonis/Core/Env';

export default Env.rules({
  OPTIONAL_STRING: Env.schema.string.optional(),
});

// in contracts/env.ts
declare module '@ioc:Adonis/Core/Env' {
  type CustomTypes = typeof import('../env').default;
  interface EnvTypes extends CustomTypes {}
}

// in some other file
import Env from '@ioc:Adonis/Core/Env';

const value = Env.get('OPTIONAL_STRING', 'defaultValue');
type ValueType = typeof value; // string | undefined

ValueType should be string because of the default value. This is important to avoid errors when passing the value returned by Env.get() to a function that requires a string.
Additionally, I think the typings should only allow to pass a default value if the key was declared as optional.

Problem with schema URL validation when using URLS without a TLD

Just realized the following

SOMEURL: Env.schema.string({format: 'url'})

if the URL is something like http://someservice:3030, which is the case when using an AdonisJS application with other services and docker-compose, it throws an error.

E_INVALID_ENV_VALUE: Value for environment variable "SOMEURL" must be a valid URL, instead received "http://someservice:3030"

Expected result: http://someservice:3030" should be valid

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.