powertools-lambda-typescript icon indicating copy to clipboard operation
powertools-lambda-typescript copied to clipboard

Feature request: Helper function for validating required environment variables

Open garysassano opened this issue 1 year ago • 1 comments

Use case

It would be helpful to have a helper function to validate that required environment variables are present and not empty. This is a common use case when developing Lambda functions, and currently requires developers to write repetitive boilerplate code. This will improve error handling and make code more robust and maintainable.

Solution/User Experience

Create a helper function getRequiredEnvVar that:

  1. Takes the name of an environment variable as a parameter
  2. Checks if the variable exists and is not empty
  3. Returns the value if it exists
  4. Throws a descriptive error if the variable is missing or empty

Example Usage

import { getRequiredEnvVar } from '@aws-lambda-powertools/commons';

// Simple usage
const dbName = getRequiredEnvVar("DB_NAME");

// With type safety
const port = getRequiredEnvVar<number>("PORT", { parser: Number });

// Multiple variables for database configuration
const credentials = {
    username: getRequiredEnvVar("DB_USER"),
    password: getRequiredEnvVar("DB_PASS"),
    host: getRequiredEnvVar("DB_HOST"),
    port: getRequiredEnvVar<number>("DB_PORT", { parser: Number })
};

// Using with custom error message
const apiKey = getRequiredEnvVar("API_KEY", {
    errorMessage: "API_KEY is required for external service integration"
});

Benefits

  • Reduces boilerplate code
  • Provides consistent error handling across applications
  • Improves code readability
  • Makes environment configuration issues more obvious during testing/deployment
  • Follows the "fail fast" principle by validating configuration early
  • Provides type safety and IntelliSense support in TypeScript projects

Implementation Notes

  • Should be added to the @aws-lambda-powertools/commons package
  • Type definition should support generic type parameter for type safety:
interface GetEnvVarOptions<T> {
    parser?: (value: string) => T;
    errorMessage?: string;
}

function getRequiredEnvVar<T = string>(
    name: string, 
    options?: GetEnvVarOptions<T>
): T;
  • Should throw a custom error type (e.g., MissingEnvironmentVariableError) for better error handling
  • Should trim whitespace from values before validation
  • Empty strings should be considered invalid by default
  • Consider adding validation for common types:
    • Numbers (integers, floats)
    • Booleans (true/false, yes/no, 1/0)
    • JSON strings that need parsing
  • Error messages should be clear and actionable, including:
    • The name of the missing/invalid variable
    • The expected format (if a parser was provided)
    • Any custom error message provided in options

Alternative solutions

No response

Acknowledgment

Future readers

Please react with 👍 and your use case to help us understand customer demand.

garysassano avatar Oct 05 '24 03:10 garysassano

Hey @garysassano , thanks for raising the issue. This is a common use case where you'd spend few lines of code to fetch and validate the environment variables that we could simplify and provide better error handling, especially for higher number of variables (10+).

The requirements and the solution remind me of https://github.com/ran-isenberg/aws-lambda-env-modeler from @ran-isenberg. Instead of calling getRequiredEnvVar multiple times, I see a better solution in having an environment object defined as a model. We could use zod parser to validate the model and also get a full error report for all environment variables.

const envSchema = z.object({
  DB_NAME: z.string(),
  DB_PORT: z.number(),
})

type MyEnvs = z.infer<typeof envSchema>;

const myEnvs: Myenvs = validateEnvs(envSchema)

const handler = async (event: unknown, context: Context) => {
  // myEnvs is available, valid and typed here
}

The main benefit we could provide is 1/ fetch a list of variables from process.env, 2/ validate against pre-defined schema 3/ output full report on all variables.

I'd like to hear more feedback from the community and customers how they approach this problem and if it's worth implementing.

am29d avatar Oct 07 '24 08:10 am29d

const envSchema = z.object({ DB_NAME: z.string(), DB_PORT: z.number(), })

type MyEnvs = z.infer<typeof envSchema>;

const myEnvs: Myenvs = validateEnvs(envSchema)

const handler = async (event: unknown, context: Context) => { // myEnvs is available, valid and typed here }

Personally I don't see what Powertools is adding here, if customers already have to provide their own schema, in the example envSchema, then they can just do this and achieve the same result:

const envSchema = z.object({
  DB_NAME: z.string(),
  DB_PORT: z.number(),
})

type MyEnvs = z.infer<typeof envSchema>;

const myEnvs: Myenvs = envSchema.parse(process.env);

const handler = async (event: unknown, context: Context) => {
  // myEnvs is available, valid and typed here
}

I'm also not a huge fan of bringing in a 3rd party dependency to read environment variables, since in practice you can only store strings and the total size of all env variables, including keys, cannot exceed 4 KB. This limits quite a lot what you can or should store in the environment.

Having a getRequiredEnvVar with simple type coercion of the most basic types, i.e. string, number, boolean, Array of the previous three, and JSON could make sense, since in practice I'd see customers as well as myself using it the way Gary suggested and exporting my own config object that is shared across modules.

dreamorosi avatar Jan 29 '25 07:01 dreamorosi

⚠️ COMMENT VISIBILITY WARNING ⚠️

This issue is now closed. Please be mindful that future comments are hard for our team to see.

If you need more assistance, please either tag a team member or open a new issue that references this one.

If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar May 22 '25 08:05 github-actions[bot]

This is now released under v2.21.0 version!

github-actions[bot] avatar Jun 03 '25 15:06 github-actions[bot]