npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ukitgroup/nestjs-config

v2.1.0-alpha.2

Published

modular config with type casting and validation out of the box

Downloads

780

Readme

nestjs-config

Travis Coverage Status npm

GitHub top language GitHub code size in bytes

license GitHub last commit

Convenient modular config for nestjs applications

  • type casting (everything in environment is string) E.g. 'true' -> boolean ...
  • runtime validation
  • compatible with typescript you will have typed configs
  • modularity - you can define configs for every module in you project
  • get configs from environment variables by design
  • convenient config definition with class-transformer/class-validator

Installation

npm install --save @ukitgroup/nestjs-config

or

yarn add @ukitgroup/nestjs-config

Short example

Override configuration for particular modules from environment

.env

CAT__WEIGHT=5

cat.config.ts

@Config('CAT')
export class CatConfig {
  @Env('WEIGHT')
  @Number()
  readonly weight: number;

  @Env('KNOWS_PROGRAMMING')
  @Boolean()
  readonly knowsProgramming: boolean = true;
}

Get the cat config in a service

cat.service.ts

@Injectable()
export class CatService {
  constructor(@Inject(CatConfig) private readonly config: CatConfig) {}

  meow(): string {
    // overridden from env
    // typeof this.config.weight === 'number'
    // this.config.weight === 5

    // default value
    // typeof this.config.knowsProgramming === 'boolean'
    // this.config.knowsProgramming === true
    return `meows..`;
  }
}

API

Define options for config in AppModule with:

ConfigModule.forRoot(options: ConfigOptions)
interface ConfigOptions {
  fromFile?: string;
  configs?: ClassType[];
  imports?: NestModule[];
  providers?: Provider[];
}

If you don't set fromFile option, process.env will be used.

In addition you can provide logger to the library to log validation errors via token CONFIG_LOGGER.

So as raw object via token RAW_CONFIG. You might need it in your tests:

const moduleFixture: TestingModule = await Test.createTestingModule({
  imports: [AppModule],
})
  .overrideProvider(RAW_CONFIG)
  .useValue({
    APP__HTTP_PORT: '3000',
    CAT__WEIGHT: '5',
  })
  .compile();

Define configs in any module with:

ConfigModule.forFeature(configs: ClassType[])

Decorators

| Decorator | Description | |-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| | Common config decorators | Import from @ukitgroup/nestjs-config | | @Config(name: string) | Add prefix to env variables | | @UnscopedConfig() | For config without prefix in env variables names | | @Env(name: string) | Extract env with name to this variable | | | | | Type decorators | Import from @ukitgroup/nestjs-config/types | | @String() | String variable (@IsString) | | @Number() | Number variable (parseFloat + @IsNumber) | | @Integer() | Integer variable (parseInt + @IsInteger) | | @Boolean() | Boolean variable ('true', 'false' + @IsBool) | | @Transform(transformFn: Function) | Custom transformation. Import from @ukitgroup/nestjs-config/transformer | | | | | Validation decorators | The same as class-validator. Import from @ukitgroup/nestjs-config/validator. |

Usage

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@ukitgroup/nestjs-config';
import { AppConfig } from './app.config';
import { CatModule } from './cat.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      fromFile: '.env',
      configs: [AppConfig],
    }),
    CatModule,
  ],
})
export class AppModule {}

Create class that describes configuration for application

app.config.ts

import { Config, Env } from '@ukitgroup/nestjs-config';
import { Integer } from '@ukitgroup/nestjs-config/types';

@Config('APP')
export class AppConfig {
  @Env('HTTP_PORT')
  @Integer()
  readonly httpPort: number = 3000;
}

Use AppConfig to configure application

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AppConfig } from './app.config';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = app.get<AppConfig>(AppConfig);

  await app.listen(config.httpPort);
}
bootstrap();

Create class that describes configuration for particular module CatsModule

cat.config.ts

import { Config, Env } from '@ukitgroup/nestjs-config';
import { Boolean, Number, String } from '@ukitgroup/nestjs-config/types';
import { Transform } from '@ukitgroup/nestjs-config/transformer';
import { IsDate, IsOptional } from '@ukitgroup/nestjs-config/validator';

@Config('CAT')
export class CatConfig {
  @Env('NAME')
  @String()
  readonly name: string;

  @Env('WEIGHT')
  @Number()
  readonly weight: number;

  @Env('KNOW_PROGRAMMING')
  @Boolean()
  readonly knowsProgramming: boolean = true;

  @Env('BIRTH_DATE')
  @Transform((value) => new Date(value))
  @IsOptional()
  @IsDate()
  readonly birthDate: Date;
}

Inject CatConfig for CatModule

cat.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@ukitgroup/nestjs-config';
import { CatConfig } from './cat.config';
import { CatsService } from './cats.service';

@Module({
  imports: [ConfigModule.forFeature([CatConfig])],
  providers: [CatsService],
})
export class CatModule {}

Get the cat config in a service

cat.service.ts

import { Inject, Injectable } from '@nestjs/common';
import { CatConfig } from './cat.config';

@Injectable()
export class CatService {
  constructor(@Inject(CatConfig) private readonly config: CatConfig) {}

  meow(): string {
    return `${this.config.name} meows..`;
  }
}

Override configuration for particular modules from environment

.env

APP__HTTP_PORT=3000
CAT__NAME=vasya
CAT__WEIGHT=5

or on launch your application

APP__HTTP_PORT=3000 CAT__NAME=vasya CAT__WEIGHT=5 node dist/main.js

Also you can see the example on GitHub.

Unscoped configs

Okay, that's cool, but what if I need more flexibility in environment variables? For example, we migrate from legacy service, and we need to use old variables names (without module__ prefix).

I don't think this approach is quite right, try not to use it, but... we have @UnscopedConfig decorator instead of @Config for this case. But really, try to use @Config decorator first 🙂

For example, we have env key LEGACY_VARIABLE, then config will be similar to this:

@UnscopedConfig()
export class LegacyConfig {
  @Env('LEGACY_VARIABLE')
  @String()
  readonly fieldOne: string;
}

Transformation

You can either use our built-in types like Integer, Boolean, etc..
Or transform value with your own rule with Transform:

CAT__YOUR_TYPE_VARIABLE=...
@Config('CAT')
class CatConfig {
  @Env('YOUR_TYPE_VARIABLE')
  @Transform(fn) // where fn is your transformation function
  myVariable: MyType;
}

We use our own version of class-transformer: @ukitgroup/class-transformer

If environment variable is empty or not provided, config will use default value.

Validation

CAT__WEIGHT=not_a_number
@Config('CAT')
class CatConfig {
  @Env('WEIGHT')
  @Number()
  weight: number;
}

Library will throw an error on launch application: Cat.weight received 'not_a_number' errors: {"IsNumber": "Should be number"}

Requirements

  1. @nestjs/common >=7.2.0
  2. @nestjs/core >=7.2.0

License

@ukitgroup/nestjs-config is MIT licensed.