Sling Academy
Home/Node.js/NestJS: How to exclude entity field from returned by controller

NestJS: How to exclude entity field from returned by controller

Last updated: January 01, 2024

Introduction

When building an API with NestJS, it’s essential to control what data is sent back to the client. At times, it’s necessary to exclude certain entity fields for security or relevancy reasons. This article dives deep into various methods to hide specific properties in a NestJS application.

Using Class Transformer

To begin with, NestJS has seamless integration with class-transformer, a powerful tool that allows us to control the serialization of objects. By adding the @Exclude() decorator to a class property, we tell NestJS to leave out this field when the class is converted to a plain object.

import { Exclude } from 'class-transformer';

class UserEntity {
  id: number;

  @Exclude()
  password: string;

  // ... other properties
}

Make sure you then use ClassSerializerInterceptor to apply the transformation globally or in a specific controller.

@Controller('users')
@UseInterceptors(ClassSerializerInterceptor)
export class UsersController {
  // ...
}

Custom Decorators for Hiding Fields

Building on the basics, we can create custom decorators that provide more flexibilty. This allows us to create on-the-fly exclusion logic tailored to specific use cases or business rules.

// CustomDecorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CustomExclude = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const response = ctx.switchToHttp().getResponse();
    response.locals.excludeFields = []; // Define logic to set fields based on context
  }
);

You can then retrieve these fields in an interceptor and manipulate the response accordingly.

Dynamic Exclusion with Interceptors

In scenarios where exclusion rules can’t be statically defined, such as when they are role-based or context-specific, we can implement an interceptor that determines what to exclude during runtime.

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

@Injectable()
export class DynamicFieldInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    // Dynamic logic to figure out which fields to exclude

    return next.handle().pipe(map(data => {
      // Exclude fields dynamically from data
      return data;
    }));
  }
}

PartialType and OmitType with Mapped Types

NestJS offers Mapped Types in the form of PartialType and OmitType that are handy when you need to derive DTOs from your entities and exclude fields without affecting the entity itself.

// user.dto.ts
import { OmitType } from '@nestjs/swagger';
import { UserEntity } from './user.entity';

export class UserDto extends OmitType(UserEntity, ['password'] as const) {
  // Now UserDto excludes the password field from UserEntity
}

Selective Exclusions with Query Builders

For ultimate control over the database response, using a Query Builder gives you fine-grained control by allowing you to specify exactly which columns to select, thereby implicitly excluding undesired ones.

// UserController.ts
// ... other imports
import { getConnection } from 'typeorm';

@Controller('users')
export class UsersController {
  // ...

  @Get()
  async findAll(): Promise<UserEntity[]> {
    return getConnection()
      .createQueryBuilder()
      .select(['user.id', 'user.name']) // Explicitly select only certain fields
      .from(UserEntity, 'user')
      .getMany();
  }
}

Conclusion

Throughout this tutorial, we’ve explored multiple avenues for excluding entity fields when responding to HTTP requests in NestJS. By harnessing decorators, interceptors, DTOs, and Query Builders, we have the tools to shape our API responses to be both secure and relevant to the consumer. As our NestJS applications grow in complexity, these techniques will be pivotal in maintaining good API hygiene.

Next Article: NestJS: Using Class Validator to validate array of objects

Previous Article: NestJS & TypeORM Import Error: ‘Cannot use import statement outside a module’

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates