CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nestjs--mongoose

NestJS module that provides seamless integration between NestJS and Mongoose ODM for MongoDB database operations

80

1.02x
Quality

Pending

Does it follow best practices?

Impact

80%

1.02x

Average score across 10 eval scenarios

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

validation-pipes.mddocs/

Validation Pipes

Pre-built pipes for validating and parsing MongoDB ObjectIds in request parameters and body data. These pipes integrate with NestJS's validation system to ensure data integrity when working with MongoDB documents.

Capabilities

IsObjectIdPipe

Validates if a string is a valid MongoDB ObjectId format without converting it to an ObjectId instance.

class IsObjectIdPipe implements PipeTransform {
  /**
   * Validates that a string is a valid MongoDB ObjectId format
   * @param value - String value to validate
   * @returns The original string if valid
   * @throws BadRequestException if invalid ObjectId format
   */
  transform(value: string): string;
}

Usage Examples:

import { Controller, Get, Param } from '@nestjs/common';
import { IsObjectIdPipe } from '@nestjs/mongoose';

@Controller('users')
export class UsersController {
  // Validate ObjectId in route parameter
  @Get(':id')
  async findOne(@Param('id', IsObjectIdPipe) id: string) {
    // id is guaranteed to be a valid ObjectId string
    return this.usersService.findById(id);
  }

  // Multiple ObjectId parameters
  @Get(':userId/posts/:postId')
  async findUserPost(
    @Param('userId', IsObjectIdPipe) userId: string,
    @Param('postId', IsObjectIdPipe) postId: string,
  ) {
    return this.postsService.findByUserAndId(userId, postId);
  }

  // Optional ObjectId validation
  @Get()
  async findAll(@Query('authorId', new IsObjectIdPipe({ optional: true })) authorId?: string) {
    if (authorId) {
      return this.usersService.findByAuthor(authorId);
    }
    return this.usersService.findAll();
  }
}

// In request body validation
import { Body, Post } from '@nestjs/common';

@Controller('comments')
export class CommentsController {
  @Post()
  async create(@Body() createCommentDto: CreateCommentDto) {
    return this.commentsService.create(createCommentDto);
  }
}

// DTO with ObjectId validation
export class CreateCommentDto {
  @IsString()
  content: string;

  @Transform(({ value }) => value, { toClassOnly: true })
  @Validate(IsObjectIdPipe)
  postId: string;

  @Transform(({ value }) => value, { toClassOnly: true })
  @Validate(IsObjectIdPipe)
  authorId: string;
}

ParseObjectIdPipe

Validates and converts a string to a MongoDB ObjectId instance for direct use with Mongoose operations.

class ParseObjectIdPipe implements PipeTransform {
  /**
   * Validates and converts a string to MongoDB ObjectId
   * @param value - String value to parse
   * @returns ObjectId instance
   * @throws BadRequestException if invalid ObjectId format
   */
  transform(value: string): Types.ObjectId;
}

Usage Examples:

import { Controller, Get, Param, Delete } from '@nestjs/common';
import { ParseObjectIdPipe } from '@nestjs/mongoose';
import { Types } from 'mongoose';

@Controller('users')
export class UsersController {
  // Parse ObjectId in route parameter
  @Get(':id')
  async findOne(@Param('id', ParseObjectIdPipe) id: Types.ObjectId) {
    // id is now a proper ObjectId instance
    return this.usersService.findById(id);
  }

  @Delete(':id')
  async remove(@Param('id', ParseObjectIdPipe) id: Types.ObjectId) {
    return this.usersService.remove(id);
  }

  // Complex route with multiple ObjectIds
  @Get(':userId/orders/:orderId/items/:itemId')
  async findOrderItem(
    @Param('userId', ParseObjectIdPipe) userId: Types.ObjectId,
    @Param('orderId', ParseObjectIdPipe) orderId: Types.ObjectId,
    @Param('itemId', ParseObjectIdPipe) itemId: Types.ObjectId,
  ) {
    return this.ordersService.findItemByIds(userId, orderId, itemId);
  }
}

// Service usage with parsed ObjectIds
@Injectable()
export class UsersService {
  constructor(@InjectModel(User.name) private userModel: Model<User>) {}

  async findById(id: Types.ObjectId): Promise<User> {
    // Can use ObjectId directly in Mongoose operations
    return this.userModel.findById(id).exec();
  }

  async findByIds(ids: Types.ObjectId[]): Promise<User[]> {
    return this.userModel.find({ _id: { $in: ids } }).exec();
  }

  async updateRelationship(userId: Types.ObjectId, friendId: Types.ObjectId): Promise<User> {
    return this.userModel.findByIdAndUpdate(
      userId,
      { $addToSet: { friends: friendId } },
      { new: true }
    ).exec();
  }
}

Advanced Pipe Usage

Custom Validation Options

import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
import { isValidObjectId, Types } from 'mongoose';

@Injectable()
export class CustomObjectIdPipe implements PipeTransform {
  constructor(private readonly options: { optional?: boolean; allowNull?: boolean } = {}) {}

  transform(value: any, metadata: ArgumentMetadata): string | Types.ObjectId | null {
    // Handle optional values
    if (this.options.optional && (value === undefined || value === '')) {
      return undefined;
    }

    // Handle null values
    if (this.options.allowNull && value === null) {
      return null;
    }

    // Validate ObjectId format
    if (!isValidObjectId(value)) {
      throw new BadRequestException(`Invalid ObjectId format: ${value}`);
    }

    // Return as string or ObjectId based on needs
    return metadata.metatype === Types.ObjectId ? new Types.ObjectId(value) : value;
  }
}

// Usage with custom options
@Controller('posts')
export class PostsController {
  @Get()
  async findAll(
    @Query('categoryId', new CustomObjectIdPipe({ optional: true })) categoryId?: string,
    @Query('authorId', new CustomObjectIdPipe({ optional: true })) authorId?: string,
  ) {
    const filters: any = {};
    if (categoryId) filters.category = categoryId;
    if (authorId) filters.author = authorId;
    
    return this.postsService.findWithFilters(filters);
  }
}

Array ObjectId Validation

@Injectable()
export class ParseObjectIdArrayPipe implements PipeTransform {
  transform(value: string | string[]): Types.ObjectId[] {
    const ids = Array.isArray(value) ? value : [value];
    
    return ids.map(id => {
      if (!isValidObjectId(id)) {
        throw new BadRequestException(`Invalid ObjectId format: ${id}`);
      }
      return new Types.ObjectId(id);
    });
  }
}

@Controller('users')
export class UsersController {
  @Post('bulk-update')
  async bulkUpdate(
    @Body('userIds', ParseObjectIdArrayPipe) userIds: Types.ObjectId[],
    @Body() updateData: any,
  ) {
    return this.usersService.bulkUpdate(userIds, updateData);
  }

  @Delete('bulk-delete')
  async bulkDelete(@Body('ids', ParseObjectIdArrayPipe) ids: Types.ObjectId[]) {
    return this.usersService.bulkDelete(ids);
  }
}

Global Pipe Configuration

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // Global validation pipe with ObjectId support
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
    }),
  );

  await app.listen(3000);
}
bootstrap();

// Custom global ObjectId validation
@Injectable()
export class GlobalObjectIdValidationPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    // Auto-detect ObjectId strings in parameters
    if (metadata.type === 'param' && typeof value === 'string' && isValidObjectId(value)) {
      return new Types.ObjectId(value);
    }
    
    return value;
  }
}

// Register globally
app.useGlobalPipes(new GlobalObjectIdValidationPipe());

Integration with Class Validators

import { IsString, IsOptional, ValidateNested, Type, registerDecorator, ValidationOptions } from 'class-validator';
import { Transform } from 'class-transformer';
import { isValidObjectId, Types } from 'mongoose';

// Custom ObjectId validator
export function IsObjectId(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: 'isObjectId',
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      validator: {
        validate(value: any) {
          return typeof value === 'string' && isValidObjectId(value);
        },
        defaultMessage() {
          return '$property must be a valid ObjectId';
        },
      },
    });
  };
}

// DTO with ObjectId validation
export class CreatePostDto {
  @IsString()
  title: string;

  @IsString()
  content: string;

  @IsObjectId()
  @Transform(({ value }) => value.toString())
  authorId: string;

  @IsOptional()
  @IsObjectId()
  @Transform(({ value }) => value ? value.toString() : undefined)
  categoryId?: string;

  @IsOptional()
  @IsObjectId({ each: true })
  @Transform(({ value }) => Array.isArray(value) ? value.map(id => id.toString()) : [])
  tagIds?: string[];
}

@Controller('posts')
export class PostsController {
  @Post()
  async create(@Body() createPostDto: CreatePostDto) {
    // All ObjectIds are validated by class-validator
    return this.postsService.create(createPostDto);
  }
}

Error Handling

The validation pipes throw standard NestJS BadRequestException when validation fails:

// Example error responses
{
  "statusCode": 400,
  "message": "Validation failed (ObjectId is expected)",
  "error": "Bad Request"
}

// Custom error handling
@Injectable()
export class CustomObjectIdPipe implements PipeTransform {
  transform(value: string): Types.ObjectId {
    if (!isValidObjectId(value)) {
      throw new BadRequestException({
        statusCode: 400,
        message: `Invalid ObjectId format: "${value}". ObjectId must be a 24 character hex string.`,
        error: 'Invalid ObjectId',
        provided: value,
      });
    }
    
    return new Types.ObjectId(value);
  }
}

docs

dependency-injection.md

index.md

module-configuration.md

schema-definition.md

schema-factories.md

utility-functions.md

validation-pipes.md

tile.json