[Nest] Nest.js Initial Setup

ยท

4 min read

[Nest] Nest.js Initial Setup

๐Ÿˆ Setup

  1. npm i @nestjs/cli - Install the Nest.js CLI library.

  2. nest new [project-name] - Create a new project.

    • If the folder is already created, use nest new ./ instead.
  3. The generated directory and files will look like this:

โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ nest-cli.json
โ”œโ”€โ”€ node_modules
โ”œโ”€โ”€ package-lock.json
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ .eslintrc.js
โ”œโ”€โ”€ .prettierrc
โ”œโ”€โ”€ src
โ”‚   โ”œโ”€โ”€ app.controller.spec.ts
โ”‚   โ”œโ”€โ”€ app.controller.ts
โ”‚   โ”œโ”€โ”€ app.module.ts
โ”‚   โ”œโ”€โ”€ app.service.ts
โ”‚   โ””โ”€โ”€ main.ts
โ”œโ”€โ”€ test
โ”‚   โ”œโ”€โ”€ app.e2e-spec.ts
โ”‚   โ””โ”€โ”€ jest-e2e.json
โ”œโ”€โ”€ tsconfig.build.json
โ””โ”€โ”€ tsconfig.json

๐Ÿˆ Controller

A controller is responsible for handling incoming requests from clients and returning responses.

  • In Nest.js, controllers handle routing using decorators such as @Post, @Get, @Put, @Patch, @Delete.

  • You can generate files and test files for a controller using nest g controller [name].

๐Ÿˆ Provider

A provider is a fundamental concept in Nest that includes services, repositories, factories, helpers, and more. Providers are objects that can be injected as dependencies. In other words, they are objects that have associations with other systems.

Service

  • The service layer contains business logic.

  • You can generate files and test files for a service using nest g service [name].

Repository

  • The repository layer contains methods for executing database queries.

  • Create repository files manually.

  • If you are using MongoDB, you can refer to this blog post for repository usage.

  • Note about TypeORM: In previous versions, the @EntityRepository decorator was used, but it has been deprecated. Instead, you need to inherit the Repository class provided by TypeORM. You can find the usage in this blog post (assuming we are using MySQL and focusing on TypeORM).

๐Ÿˆ Module

Modules are used by Nest to manage the application structure by providing metadata. Each application has one or more root modules, which define the relationships and dependencies between modules and providers.

  • You can generate module files using npm g module [name].

  • For TypeORM, you need to modify the module.ts files of each module as follows:

@Module({
  imports: [TypeOrmModule.forFeature([EntityName])],
  controllers: [SomethingController],
  providers: [SomethingService, SomethingRepository],
})
export class HospitalsModule {}
  • Add TypeOrmModule.forFeature([EntityName]) to the imports array.

  • Add repositories to the providers array.

๐Ÿˆ main.ts File

const logger = new Logger();
const app = await NestFactory.create(AppModule);

// Global validation pipe
app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true, // Automatically remove properties that do not exist in the payload and DTO class
    forbidNonWhitelisted: true, // Throw an exception instead of removing disallowed properties
    transform: true, // Automatically transform the payload received over the network into the designated object based on the DTO class
  }),
);

// Global HTTP exception filter
app.useGlobalFilters(new HttpExceptionFilter()); // Global filter

// CORS
app.enableCors();

// Config
const config = app.get<ConfigType<typeof appConfig>>(appConfig.KEY);
const port = config.port;
await app.listen(port);
if (config.mode === 'development') logger.log(`Server is running on port ${port}`);
  • Basic CORS settings are added.

  • The global validation pipe (validation & transformation) is defined. (Requires installation of the following libraries: npm i --save class-validator class-transformer)

๐Ÿˆ Config Environment Variable Management

  • Install the following packages: npm i --save @nestjs/config cross-env joi.

  • You can access environment variables using the ConfigService and ConfigType provided by the ConfigModule. Using ConfigType allows you to read environment variables in a more type-safe manner and makes it easier to manage environment variables by separating them by functionality.

  • Reference site: https://www.daleseo.com/nestjs-configuration/

๐Ÿˆ HTTP Request Logger Middleware Configuration

  • In app.module.ts, configure the middleware as follows. It will log requests only in development mode.
export class AppModule implements NestModule {
  private readonly isDev: boolean = process.env.MODE === 'development' ? true : false;

  // Log HTTP requests in dev mode
  configure(consumer: MiddlewareConsumer) {
    if (this.isDev) {
      consumer.apply(HTTPLoggerMiddleware).forRoutes('*');
    }
  }
}
  • Here's an example of HTTP-logger.middleware.ts:
@Injectable()
export class HTTPLoggerMiddleware implements NestMiddleware {
  private logger = new Logger('HTTP'); // Logger for HTTP protocol
  use(req: Request, res: Response, next: NextFunction) {
    // Log when the response is finished (finish event)
    res.on('finish', () => {
      this.logger.log(`${req.ip} ${req.method}, ${res.statusCode}`, req.originalUrl);
    });
    next();
  }
}

๐Ÿˆ HTTP Exception Filter

Nest.js provides built-in exception filtering for handling HTTP responses. For example, if a server error occurs, Nest will throw an error response like this:

{
  "statusCode": 500,
  "message": "Internal server error"
}

You can use an exception filter to handle such error responses that are thrown either by Nest.js itself or by using throw new HttpException() to customize the response.

import { Catch, HttpException } from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter {
  catch(exception, host) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();
    const status = exception.getStatus();
    const error = exception.getResponse() as string | { error: string; statusCode: number; message: string | string[] };

    // Handling error thrown using `throw new HttpException()`
    if (typeof error === 'string') {
      response.status(status).json({


        success: false,
        error,
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
    }
    // Handling error responses handled by Nest itself
    else {
      response.status(status).json({
        success: false,
        ...error,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
    }
  }
}
ย