DEV Community

Munisekhar Udavalapati
Munisekhar Udavalapati

Posted on

1

Mastering Decorators in NestJS: A Comprehensive Guide

What Are Decorators?

Decorators are functions that add metadata to a class, method, or property at runtime. In NestJS, they play a crucial role in defining routes, injecting dependencies, applying guards, and more.

Built-in Decorators in NestJS
NestJS provides several built-in decorators to simplify application development:

1. Routing Decorators

@Controller(): Defines a controller for handling requests.
@Get(), @post(), @Put(), @Delete(): Define route handlers for HTTP methods.
Example:

Copy code
@Controller('users')
export class UserController {
  @Get()
  findAll() {
    return 'This action returns all users';
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Request Object Decorators @body(): Access the request body. @Query(): Access query parameters. @param(): Access route parameters. Example:
Copy code
@Post()
createUser(@Body() createUserDto: CreateUserDto) {
  return `User ${createUserDto.name} created!`;
}
3. Dependency Injection Decorators
@Injectable(): Marks a class as a provider for DI.
@Inject(): Explicitly inject a specific dependency.
Creating Custom Decorators
For advanced use cases, you can create custom decorators to encapsulate reusable logic. Heres how:

Example: Extracting a Token
Create a custom decorator using createParamDecorator:
typescript
Copy code
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const ExtractToken = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const authHeader = request.headers['authorization'];
    if (authHeader && authHeader.startsWith('Bearer ')) {
      return authHeader.slice(7);
    }
    return null;
  },
);
Enter fullscreen mode Exit fullscreen mode

Use the decorator in your controller:


@Controller('auth')
export class AuthController {
  @Get('profile')
  getProfile(@ExtractToken() token: string) {
    return `Token: ${token}`;
  }
}
Enter fullscreen mode Exit fullscreen mode

Why Use Custom Decorators?
Custom decorators improve code reusability, readability, and maintainability. Instead of repeating logic across controllers, encapsulate it in a decorator for consistent and cleaner code.

Tips for Using Decorators in NestJS
Understand Execution Contexts: Decorators like createParamDecorator provide access to request objects, making them ideal for extracting and transforming data.
Leverage Metadata: Use libraries like class-validator to define validation decorators.
Combine Decorators: Use multiple decorators for complex functionalities, such as guards, interceptors, and filters.
Conclusion
Decorators in NestJS offer powerful tools for building clean, scalable applications. Whether you're using built-in decorators or creating custom ones, mastering them will take your NestJS skills to the next level.

Learn More
Official NestJS Docs: Custom Decorators
OpenAPI Integration: Swagger Decorators

import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';

// DTO for creating or updating users
class CreateUserDto {
  name: string;
  email: string;
}

@Controller('users') // Base route: '/users'
export class UserController {
  private users = []; // Example in-memory users array for demonstration

  // GET /users
  @Get()
  findAll() {
    return this.users;
  }

  // GET /users/:id
  @Get(':id')
  findOne(@Param('id') id: string) {
    const user = this.users.find(user => user.id === id);
    return user || { message: `User with ID ${id} not found` };
  }

  // POST /users
  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    const newUser = { id: `${Date.now()}`, ...createUserDto };
    this.users.push(newUser);
    return { message: 'User created', user: newUser };
  }

  // PUT /users/:id
  @Put(':id')
  update(@Param('id') id: string, @Body() updateUserDto: CreateUserDto) {
    const userIndex = this.users.findIndex(user => user.id === id);
    if (userIndex === -1) {
      return { message: `User with ID ${id} not found` };
    }
    this.users[userIndex] = { id, ...updateUserDto };
    return { message: 'User updated', user: this.users[userIndex] };
  }

  // DELETE /users/:id
  @Delete(':id')
  delete(@Param('id') id: string) {
    const userIndex = this.users.findIndex(user => user.id === id);
    if (userIndex === -1) {
      return { message: `User with ID ${id} not found` };
    }
    const deletedUser = this.users.splice(userIndex, 1);
    return { message: 'User deleted', user: deletedUser };
  }
}

Enter fullscreen mode Exit fullscreen mode

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

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