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

SurveyJS custom survey software

Build Your Own Forms without Manual Coding

SurveyJS UI libraries let you build a JSON-based form management system that integrates with any backend, giving you full control over your data with no user limits. Includes support for custom question types, skip logic, an integrated CSS editor, PDF export, real-time analytics, and more.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay