Reputation:
I want to create a NestJs API with TypeORM and MongoDB. My entity id fields are of type ObjectID
. The controller routes should validate the incoming ids before passing them to the services. I know that Nest ships with the ParseIntPipe and ParseUUIDPipe but as far as I know there is nothing I can use for MongoDBs ObjectID
.
So I created my own pipe for those fields as described here https://docs.nestjs.com/pipes#transformation-use-case
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
import { ObjectID } from 'typeorm';
@Injectable()
export class ParseObjectIdPipe implements PipeTransform<any, ObjectID> {
transform(value: any): ObjectID {
const validObjectId: boolean = ObjectID.isValid(value);
if (validObjectId) {
throw new BadRequestException('Invalid ObjectId');
}
const objectId: ObjectID = ObjectID.createFromHexString(value);
return objectId;
}
}
and hope this will do the trick, even for edge cases. I can use it for my route params like
@Get(':id')
public getUserById(@Param('id', ParseObjectIdPipe) id: ObjectID): Promise<User> {
return this.usersService.getUserById(id);
}
The problem I have is that some routes need a Body
validation. I use the class-validator package as described here
https://docs.nestjs.com/techniques/validation
It seems that I have to create my own class-validator decorator for those ObjectID
fields but that should be fine. Maybe I'll find something here on how to do it https://github.com/typestack/class-validator#custom-validation-classes. But how can I transform those fields to the type ObjectID
? Can I use the custom pipe for that later on too?
Update:
I also tried to transform the value via class-transformer package. So the code for this is
import { ObjectID } from 'typeorm';
import { Type, Transform } from 'class-transformer';
import { BadRequestException } from '@nestjs/common';
export class FooDTO {
@Type(() => ObjectID)
@Transform(bar => {
if (ObjectID.isValid(bar)) {
throw new BadRequestException('Invalid ObjectId');
}
return ObjectID.createFromHexString(bar);
})
public bar: ObjectID;
}
Unfortunately the value bar
is always undefined
. But maybe this code might help for validation and transformation purposes...
Upvotes: 10
Views: 13951
Reputation: 31
class-validator provides IsMongoId decorator
import { IsMongoId } from 'class-validator';
export class FooDTO {
@IsMongoId()
objectId: string;
}
Upvotes: 0
Reputation: 21
Just create on pipe of object id in code by using below code :
import { PipeTransform, Injectable, BadRequestException } from
'@nestjs/common';
import { ObjectID } from 'mongodb';
@Injectable()
export class ParseObjectIdPipe implements PipeTransform<any, ObjectID> {
public transform(value: any): ObjectID {
try {
const transformedObjectId: ObjectID = ObjectID.createFromHexString(value);
return transformedObjectId;
} catch (error) {
throw new BadRequestException('Validation failed (ObjectId is expected)');
}
}
}
and add piple in controller method :
@Post('cat/:id')
async cat(
@Param('id', ParseObjectIdPipe) id: ObjectId,
@Res() res,
@Body() cat: catDTO[],)
Upvotes: 2
Reputation: 81
For the class-transformer approach this worked for me
import { IsNotEmpty } from "class-validator";
import { Type, Transform } from 'class-transformer';
import { Types } from "mongoose"
export class CreateCommentDto {
@IsNotEmpty()
@Type(() => Types.ObjectId)
@Transform(toMongoObjectId)
articleId: Types.ObjectId
with this definition for 'toMongoObjectId':
export function toMongoObjectId({ value, key }): Types.ObjectId {
if ( Types.ObjectId.isValid(value) && ( Types.ObjectId(value).toString() === value)) {
return Types.ObjectId(value);
} else {
throw new BadRequestException(`${key} is not a valid MongoId`);
}
}
Upvotes: 8
Reputation: 91
I took your code and changed some parts. I tested it, It works fine.
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
import { Types } from 'mongoose';
@Injectable()
export class ParseObjectIdPipe implements PipeTransform<any, Types.ObjectId> {
transform(value: any): Types.ObjectId {
const validObjectId = Types.ObjectId.isValid(value);
if (!validObjectId) {
throw new BadRequestException('Invalid ObjectId');
}
return Types.ObjectId.createFromHexString(value);
}
}
Upvotes: 9
Reputation: 323
You are getting undefined because you are importing from wrong lib. you need to change this:
import { ObjectID } from 'typeorm';
for this:
import { ObjectID } from 'mongodb';
Upvotes: 1