Skip to content

Instantly share code, notes, and snippets.

@aaabramov
Last active May 23, 2023 15:35
Show Gist options
  • Save aaabramov/9d42b26e42c431364d08fadd706105fd to your computer and use it in GitHub Desktop.
Save aaabramov/9d42b26e42c431364d08fadd706105fd to your computer and use it in GitHub Desktop.
Typical NestJS app dependecies

Generate new service

See First steps in NestJS

nest new <service_name>

Most of the services need these dependencies:

npm install \
  class-validator \
  class-transformer \
  @nestjs/typeorm \
  typeorm \
  pg \
  @nestjs/terminus \
  @nestjs/config \
  @nestjs/swagger \
  swagger-ui-express \
  dotenv
  
npm install --save-dev \
  @types/validator \
  @types/express

Need authentication?

See Authentication guide

Install dependencies

npm install \
  @nestjs/passport passport \ # passport-local OR passport-google-oauth20
  @nestjs/jwt \
  passport-jwt

npm install --save-dev \
  @types/passport-local \
  @types/passport-jwt

Hashing passwords?

See Encryption and Hashing guide

Install dependencies

npm install \
  bcrypt

npm i --save-dev \
  @types/bcrypt

Usage

import * as bcrypt from 'bcrypt';

export class CryptoService {
  public static createHash(plaintext: string): string {
    return bcrypt.hashSync(plaintext, 10);
  }

  public static compare(plaintext: string, hash: string): boolean {
    return bcrypt.compareSync(plaintext, hash);
  }
}

See nest-winston package

Install dependencies

npm install \
  nest-winston \
  winston

Configure logging

main.ts

import { AppModule } from './app.module';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';

const app = await NestFactory.create(AppModule);
app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));

app.module.ts

import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp({ format: 'MM-DD-YYYY HH:mm:ss.SSS' }),
            winston.format.align(),
            winston.format.printf((info) => {
              const ctx = info.context ? ` ${info.context} -` : '';
              return `[${info.level.substring(0, 1).toUpperCase()}] ${
                info.timestamp
              }${ctx} ${info.message}`;
            }),
          ),
        }),
      ],
      level: 'debug',
    }),
    // other modules...
  ],
})
export class AppModule {}

Usage

@Injectable()
export class MyService {
  private readonly logger = new Logger(MyService.name);
}

See nestjs-telegraf package

Install dependencies

npm install \
  nestjs-telegraf \
  telegraf

See HTTP module guide

Install dependencies

npm install \
  @nestjs/axios

Usage

import { Injectable } from '@nestjs/common';
import axios, { AxiosInstance } from 'axios';

export type PersonId = number;

export interface Person {
  name: string;
  age: number;
}

@Injectable()
export class PeopleService {

  private readonly http: AxiosInstance = axios.create({
    baseURL: `http://example.com/api/v1`,
  });

  async findPerson(id: PersonId): Promise<Person> {
    const response = await this.http.get<Person>(`/people/${id}`);
    return response.data;
  }
  
}

See uuid package

Install dependecies

npm install \
  uuid

npm i --save-dev \
  @types/uuid

See Task scheduling guide

Install dependencies

npm install --save \ 
  @nestjs/schedule
npm install --save-dev \
  @types/cron

See Rate limiting guide

In-memory adapter (default)

Please note this kind of adapter is not recommended for replicated environment, e.g. running 2+ app instances.

Install dependencies

npm i --save \
  @nestjs/throttler

Redis adapter

Install dependencies

Note that there may by conflicts with typeorm package. You may specify --force option during installation.

npm install --save \
  nestjs-throttler-storage-redis \
  ioredis

Usage

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { ThrottlerStorageRedisService } from 'nestjs-throttler-storage-redis';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    ThrottlerModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        limit: config.get<number>('THROTTLE_LIMIT'),
        ttl: config.get<number>('THROTTLE_TTL'),
        storage: new ThrottlerStorageRedisService({
          host: config.get<string>('REDIS_HOST'),
          port: config.get<number>('REDIS_PORT'),
        }),
      }),
    }),
  ],
})
export class AppModule {}

app.controller.ts

import { Controller, Get, UseGuards } from '@nestjs/common';
import { ThrottlerGuard } from '@nestjs/throttler';

@Controller()
export class AppController {

  @Get()
  @UseGuards(ThrottlerGuard)
  async hello(): Promise<any> {
    return 'ok';
  }
}

See ioredis

Install dependencies

npm install --save \
  ioredis
  
npm install --save-dev \
  @types/ioredis

Usage

import Redis from 'ioredis';
import IORedis from 'ioredis';

@Injectable()
export class RedisFacade {
  private readonly redis: IORedis.Redis;

  constructor(private readonly config: ConfigService) {
    this.redis = new Redis({
      host: config.get<string>('REDIS_HOST'),
      port: config.get<number>('REDIS_PORT'),
    });
  }

  async set<V extends object>(
    key: string,
    value: V,
  ) {
    return this.redis.set(
      key,
      JSON.stringify(value),
    );
  }

  async get<V extends object>(
    key: string,
  ): Promise<V | undefined> {
    const value = await this.redis.get(key);
    if (!value) {
      return undefined;
    }

    return JSON.parse(value) as V;
  }

  async del(
    key: string,
  ): Promise<void> {
    await this.redis.del(key);
  }
  
}

See Healthchecks (Terminus)

Install dependencies

npm install --save \
  @nestjs/terminus

Usage

import { Controller, Get } from '@nestjs/common';
import {
  HealthCheck,
  HealthCheckResult,
  HealthCheckService,
  TypeOrmHealthIndicator,
} from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  constructor(
    private readonly health: HealthCheckService,
    private readonly db: TypeOrmHealthIndicator,
  ) {}

  @Get()
  @HealthCheck()
  async check(): Promise<HealthCheckResult> {
    return this.health.check([
      () => this.db.pingCheck('database')
    ]);
  }
}

See Harnessing the power of TypeScript & GraphQL

Install dependencies

npm install --save \
  @nestjs/graphql \
  @nestjs/apollo \
  @apollo/server \
  graphql

TODO

See nestjs-prometheus

Install dependencies

npm install --save \
  @willsoto/nestjs-prometheus \
  prom-client

Usage

import { Module } from '@nestjs/common';
import { PrometheusModule } from '@willsoto/nestjs-prometheus';

@Module({
  imports: [PrometheusModule.register()],
  providers: [
    makeCounterProvider({
      name: 'metric_name',
      help: 'metric_help',
      labelNames: ['label_1', 'label_2'],
    }),
  ],
})
export class AppModule {}
import { Injectable } from '@nestjs/common';
import { InjectMetric } from '@willsoto/nestjs-prometheus';
import { Counter } from 'prom-client';

@Injectable
export class Service {

  constructor(
    @InjectMetric('metric_name') private readonly counter: Counter<string>,
  ) {}

  public foo() {
    // NOTE: label values count must be the same as labels count in `makeCounterProvider`
    this.counter.labels('value1', 'value2').inc();
  }
}

Scrap metrics

http http://localhost:3000/metrics

# HELP process_cpu_user_seconds_total Total user CPU time spent in seconds.
# TYPE process_cpu_user_seconds_total counter
process_cpu_user_seconds_total 0.28837199999999996

# ...
# ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment