DEV Community

Cover image for NestJs Backend Overview
Taki (Kieu Dang)
Taki (Kieu Dang)

Posted on

5

NestJs Backend Overview

NestJS is a powerful and versatile framework for building scalable and maintainable server-side applications. It is built with TypeScript, leverages strong typing, and combines the best features of Object-Oriented Programming (OOP), Functional Programming (FP), and Reactive Programming (RP). Here's a deep dive into everything you need to know about NestJS for backend development:


1. Core Concepts of NestJS

1.1 Modularity

  • Modules: The fundamental building blocks of a NestJS app. Every application has at least one root module (AppModule), and additional modules can be created to organize features.
    • Defined with the @Module() decorator.
    • Enables separation of concerns and scalability by encapsulating services, controllers, and providers.

Example:

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  imports: [],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}
Enter fullscreen mode Exit fullscreen mode

1.2 Dependency Injection (DI)

  • NestJS heavily relies on DI for managing dependencies.
  • Providers are registered in the module and can be injected wherever needed.
  • Promotes clean, testable, and maintainable code.

Example:

@Injectable()
export class UsersService {
  constructor(private readonly httpClient: HttpService) {}
}
Enter fullscreen mode Exit fullscreen mode

1.3 Controllers

  • Handle incoming requests and send responses.
  • Defined with the @Controller() decorator.
  • Use decorators like @Get(), @Post(), etc., to define routes.

Example:

@Controller('users')
export class UsersController {
  @Get()
  findAll() {
    return 'This will return all users';
  }
}
Enter fullscreen mode Exit fullscreen mode

1.4 Services

  • Encapsulate business logic and data manipulation.
  • Defined as @Injectable() to be injected into controllers or other services.

Example:

@Injectable()
export class UsersService {
  private users = [{ id: 1, name: 'John Doe' }];

  findAll() {
    return this.users;
  }
}
Enter fullscreen mode Exit fullscreen mode

1.5 Middleware

  • Functions that can manipulate the request/response before reaching the controller.
  • Use @Injectable() and app.use() for implementation.

Example:

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

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    console.log('Request logged:', req.method, req.url);
    next();
  }
}
Enter fullscreen mode Exit fullscreen mode

1.6 Interceptors

  • Transform data before sending it to the client or after receiving a request.
  • Implement NestInterceptor and use @UseInterceptors().

Example:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(map(data => ({ data, timestamp: new Date().toISOString() })));
  }
}
Enter fullscreen mode Exit fullscreen mode

1.7 Providers and Dependency Scope

  • Providers: Anything that can be injected via DI (e.g., services, repositories).
  • Scope:
    • Singleton (default): One instance across the app.
    • Request or Transient: Custom behavior for request-specific providers.

Custom Provider Example:

const myProvider = {
  provide: "CUSTOM_TOKEN",
  useValue: { key: "value" },
};

@Module({
  providers: [myProvider],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

1.8 Lifecycles and Hooks

NestJS provides lifecycle hooks for components like modules and services:

  • OnModuleInit: Triggered when a module is initialized.
  • OnApplicationBootstrap: Called when the app starts.

Example:

@Injectable()
export class AppService implements OnModuleInit {
  onModuleInit() {
    console.log("Module initialized!");
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Advanced Features of NestJS

2.1 Validation with Pipes

  • Pipes are used for validation and transformation.
  • NestJS provides a built-in ValidationPipe to validate incoming requests.

Example:

import { IsString } from 'class-validator';

export class CreateUserDto {
  @IsString()
  readonly name: string;
}

@Controller('users')
export class UsersController {
  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return createUserDto;
  }
}
Enter fullscreen mode Exit fullscreen mode

2.2 Guards

  • Used for authorization logic.
  • Implement CanActivate and use @UseGuards().

Example:

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    return request.headers['authorization'] ? true : false;
  }
}
Enter fullscreen mode Exit fullscreen mode

2.3 Filters (Exception Handling)

  • Handle errors and exceptions globally or locally.
  • Use @Catch() to create custom exception filters.

Example:

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      message: exception.message,
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

2.4 Events with Event Emitters

  • Built-in event emitter for pub/sub patterns.

Example:

@Injectable()
export class NotificationService {
  constructor(private eventEmitter: EventEmitter2) {}

  sendNotification(data: string) {
    this.eventEmitter.emit('notification', data);
  }
}
Enter fullscreen mode Exit fullscreen mode

2.5 File Uploads

  • Use @nestjs/platform-express for file uploads.

Example:

@Controller('files')
export class FilesController {
  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log(file);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Integration with External Libraries

3.1 MongoDB

  • Integrate using @nestjs/mongoose.

Example:

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost/nest'),
    MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

3.2 Authentication (Passport.js & JWT)

  • Use @nestjs/passport and @nestjs/jwt for authentication.

Example:

import { JwtModule } from '@nestjs/jwt';

@Module({
  imports: [JwtModule.register({ secret: 'secretKey' })],
})
export class AuthModule {}
Enter fullscreen mode Exit fullscreen mode

5. Deployment Best Practices

  • Use environment variables for sensitive data (ConfigModule from @nestjs/config).
  • Bundle the app using Webpack or Dockerize it for production.
  • Use PM2 or similar tools to manage processes.


6. Design Patterns

  1. Modular Design: Split features into modules for scalability.
  2. SOLID Principles: Use DI to follow single responsibility and open/closed principles.
  3. DTOs: Define input/output structures to maintain type safety.
  4. Clean Architecture: Separate controllers, services, and repositories.

7. Folder Structure

src/
├── modules/
│   ├── auth/
│   │   ├── auth.controller.ts
│   │   ├── auth.service.ts
│   │   ├── auth.module.ts
│   ├── user/
│       ├── user.controller.ts
│       ├── user.service.ts
│       ├── user.module.ts
├── common/
│   ├── filters/
│   ├── guards/
│   ├── interceptors/
│   ├── pipes/
├── main.ts
├── app.module.ts
Enter fullscreen mode Exit fullscreen mode

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay