@webundsoehne/nestjs-util
TypeScript icon, indicating that this package has built-in type declarations

7.1.7 • Public • Published

Web und Söhne - Logo

Web & Söhne is Austria's leading expert in programming and implementing complex and large web projects.

@webundsoehne/nestjs-util

Version Downloads/week Dependencies semantic-release

Description

This is a collection of useful modules for creating a NestJS project. Mostly all of these modules are used by the in-house boilerplate of Web & Söhne.

Modules

Decorators

Retry Decorator

Wrap a class method with this decorator to retry it couple of more times. Useful for external service dependent tasks.

@Timeout(MigrationTask.name, 0)
@Retry({
  name: MigrationTask.name,
  retry: 24,
  interval: 3 * 1000
})
async migrate(): Promise<void> {
  try {
    await this.connection.runMigrations({ transaction: 'all' })
  } catch (error) {
    this.logger.error(error.message)

    throw error
  }
}

UseMaintenanceLocker Decorator

Whenever the given class method fires, it will also activate the maintenance mode through MaintenanceModule. For this MaintenanceModule should be injected in to the context of the given module.

@Timeout(MigrationTask.name, 0)
@UseMaintenanceLocker(MigrationTask.name)
async migrate(): Promise<void> {
  try {
    await this.connection.runMigrations({ transaction: 'all' })
  } catch (error) {
    this.logger.error(error.message)

    throw error
  }
}

Filters

We implemented a generic ExceptionFilter called GlobalExceptionFilter, which catches all errors and sets the payload to a userfriendly information. The real exception and stacktrace will be just logged in debug logger mode.

Usage

import { GlobalExceptionFilter } from '@webundsoehne/nestjs-util'

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: GlobalExceptionFilter
    }
  ]
})
class ServerModule implements NestModule {}

Reporting to sentry.io

GlobalSentryExceptionFilter extends the functionality of the GlobalExceptionFilter with additional reporting of errors to sentry.io. The options for sentry need to be set in the config file. At least the dsn has to be defined for a successful initialization. If the initialization was not successful, a warning will be displayed and the filter behaves as the base GlobalExceptionFilter. By default, only unhandled or critical exceptions with HTTP statuscode >= 500 will be reported. Setting the optional config param reportAll to true will report all exceptions to sentry e.g. HttpExceptions, AuthorizationExceptions etc.

This filter requires the @sentry/node package to be installed in your project. Please add it to your package.json dependencies.

Example sentry config

sentry:
  dsn: https://asdf13373r3p0rt1ng@o123456.ingest.sentry.io/12312345
  environment: appname_production
  reportAll: false

Http

The HttpExceptionFilter extends from the GlobalExceptionFilter and just catches all HttpException errors. It just overwrites the protected payload() method, which builds the message for the user.

Usage

import { HttpExceptionFilter, GlobalExceptionFilter } from '@webundsoehne/nestjs-util'

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: GlobalExceptionFilter
    },
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter
    }
  ]
})
class ServerModule implements NestModule {}

Bad-Request

The BadRequestExceptionFilter extends from the GlobalExceptionFilter and just catches BadRequestException errors. This will handle the complex validation error messages (ValidationError) in the overwritten payload() method, which just happens on BadRequestException errors.

We don't handle them in the normal HttpExceptionFilter because of performance reasons.

Usage

I hope you recognized that the order of the exception filters is relevant and required.

import { BadRequestExceptionFilter, HttpExceptionFilter, GlobalExceptionFilter } from '@webundsoehne/nestjs-util'

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: GlobalExceptionFilter
    },
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter
    },
    {
      provide: APP_FILTER,
      useClass: BadRequestExceptionFilter
    }
  ]
})
class ServerModule implements NestModule {}

Middleware

The middleware of the maintenance module uses directly the MaintenanceService to check if there exists a lock file and raises the correct exception. You will see the implementation in the usage block above.

Info-Header

The information header middleware is a really short NestMiddleware which set the X-Api-Name and X-Api-Version response header out of the process.env data. Both environment variables will be set with the setEnvironmentVariables util function, which loads the information from the package.json.

Usage

import { SetApiInfoHeaderMiddleware, setEnvironmentVariables } from '@webundsoehne/nestjs-util'

class ServerModule implements NestModule {
  async configure(consumer: MiddlewareConsumer): Promise<any> {
    await setEnvironmentVariables()

    consumer.apply(SetApiInfoHeaderMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL })
  }
}

Modules

Maintenance

The maintenance module gives you the possibility to generate and remove a lock file, as well as checking if the lock file exists and throwing a preconfigured ServiceUnavailableException error. You may use the maintenance module anywhere in your project, e.g. for database migrations.

Usage

import { MaintenanceMiddleware, MaintenanceModule } from '@webundsoehne/nestjs-util'

@Module({
  imports: [MaintenanceModule]
})
class ServerModule implements NestModule {
  async configure(consumer: MiddlewareConsumer): Promise<any> {
    consumer.apply(MaintenanceMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL })
  }
}

Methods

Name Return Description
enable void Create the configured lock file
disable void Remove the generated lock file
isEnabled Boolean Check if there is already a lock file
throwException void Throw the preconfigured exception

Configuration

If there is no misc.maintenanceNotification set, it will be generated with following template string:
`${url.basePath} is currently down for maintenance`

Key Type Default Description
url.basePath String The base API url of your project
misc.maintenanceNotification String (see hint above) The notification, which will be thrown in case of maintenance
misc.lockfile String 'maintenance.lock' The filepath of the projects's maintenance lock file

Providers

Config

This is a NestJS service which allows you to use the great config library with decorators. For scripts or in common no classes, you can use it normally too.

Important

The @Configurable() has to be the last decorator before the function is initiated.

Usage

import { ConfigParam, ConfigService, Configurable, InjectConfig } from '@webundsoehne/nestjs-util'

// 1. the old (static) way
const configValue1 = ConfigService.get('value')

class CustomService {
  // 2. inject the whole config service, normally you wont use this ways
  constructor ( @InjectConfig() private readonly config: ConfigService) {
    const configValue2 = this.config.get('value')
  }

  // 3. load the config directly as function parameter
  @AnythingElse()
  @Configurable()
  testConfig (@ConfigParam('value', 'default-value') value3?: string) {
    ...
  }
}

Logger

Customized logger service, which uses winston for nicer output.

Usage

Set an instance of the logger to the application during creation as part of the NestApplicationOptions.

import { LoggerService } from '@webundsoehne/nestjs-util'

const app = await NestFactory.create<INestApplication>(ServerModule, new FastifyAdapter(), {
  logger: new LoggerService()
})

After the logger got set to the application, all NestJS logging output will be handled by our customized logger.

import { Logger } from '@nestjs/common'

class CustomService {
  private readonly logger: Logger = new Logger(this.constructor.name)
  private readonly loggerWithoutContext: Logger = new Logger()

  constructor() {
    this.logger.verbose('log message')
    // [2020-01-01T12:00:00.000Z] [verbose] [CustomService] - log message
    this.logger.verbose('log message, with custom context', 'ForcedContext')
    // [2020-01-01T12:00:00.000Z] [verbose] [ForcedContext] - log message, with custom context

    this.logger.loggerWithoutContext('log message')
    // [2020-01-01T12:00:00.000Z] [verbose] [LoggerService] - log message
    this.logger.loggerWithoutContext('log message, with custom context', 'ForcedContext')
    // [2020-01-01T12:00:00.000Z] [verbose] [ForcedContext] - log message, with custom context
  }
}

Pipes

Extended pipes provide capabilities over the default ones for better interacting with this library.

Validation Pipe

This validation pipe extends the default pipe for class-validator while it also provides a way to override the settings for a given path utilizing the accompanying decorator.

Usage

This can either be used with a useClass or to extend the options useFactory. The default ValidationPipeOptions are { whitelist: true }.

import { Module } from '@nestjs/common'
import { APP_PIPE } from '@nestjs/core'
import { ExtendedValidationPipe } from '@webundsoehne/nestjs-util'

@Module({
  providers: [
    {
      provide: APP_PIPE,
      useClass: ExtendedValidationPipe
    }
  ]
})
export class ServerModule {}

Stay in touch

Readme

Keywords

Package Sidebar

Install

npm i @webundsoehne/nestjs-util

Weekly Downloads

557

Version

7.1.7

License

ISC

Unpacked Size

120 kB

Total Files

99

Last publish

Collaborators

  • ws-admin
  • dabls