I have a little problem with my project using GraphQL and Mongoose (code-first approach). I have a findCurrentUser query in my user’s resolver that returns the information about the currently authenticated user, but I don’t want to return the user’s password, how I can avoid this?
User’s Resolver:
@Query(() => User)
@UseGuards(GqlAuthGuard)
async findCurrentUser(@CurrentUser() user: JwtPayload): Promise<User> {
return await this.usersService.findCurrent(user.id);
}
User’s Service:
async findCurrent(id: string): Promise<User> {
try {
// find the user
const user = await this.userModel.findOne({ _id: id });
// if the user does not exists throw an error
if (!user) {
throw new BadRequestException('User not found');
}
// we should not return the user's password
// TODO: this is a temporary solution, needs to be improved
user.password = '';
return user;
} catch (error) {
throw new InternalServerErrorException(error.message);
}
}
User’s Entity:
import { ObjectType, Field, ID } from '@nestjs/graphql';
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document, Schema as MongooseSchema } from 'mongoose';
import { nanoid } from 'nanoid';
@Schema()
@ObjectType()
export class User {
@Field(() => ID)
_id: MongooseSchema.Types.ObjectId;
@Field(() => String, { nullable: false })
@Prop({ type: String, required: true, trim: true })
firstName: string;
@Field(() => String, { nullable: true })
@Prop({ type: String, required: false, trim: true })
lastName?: string;
@Field(() => String, { nullable: true })
@Prop({ type: String, required: false, default: nanoid(10) })
username: string;
@Field(() => String, { nullable: false })
@Prop({
type: String,
unique: true,
required: true,
lowercase: true,
trim: true
})
email: string;
@Field(() => String, { nullable: false })
@Prop({ type: String, required: true, trim: true, minlength: 6 })
password: string;
@Field(() => Boolean, { defaultValue: true })
@Prop({ type: Boolean, default: true })
isActive: boolean;
@Field(() => Date, { defaultValue: Date.now() })
@Prop({ type: Date, default: Date.now() })
createdAt: Date;
}
export type UserDocument = User & Document;
export const UserSchema = SchemaFactory.createForClass(User);
In the documentation, the NestJS team mentions "Serialization, " but I already tried and didn’t work. I get the following error on my GraphQL Playground:
"message": "Cannot return null for non-nullable field User._id."
0
3 Answers
You can avoid returning the password, by setting select
Prop option to false.
@Prop({ ..., select: false })
password: string;
If you don’t want to return the password on operations other than a simple select (API create/update/login etc.), you can change the document’s toJSON transform method as following :
//
UserSchema.set('toJSON', {
transform: (doc, ret, opt) => {
delete ret.password;
return ret;
}
});
In your frontend where you are defining the query you can just remove the password field like below
Before (When you were getting the password).
const user = gql`
query getUserDetails($email: String!, $name: String!, ...any other thing that you want to send to server[backend] ) {
getUserDetails(email: $email, password: $password, ...any other thing that you
want to send to server[backend] ) {
id
name
email
password
}
}
`;
After (if you don’t want the password to be returned).
const user = gql`
query getUserDetails($email: String!, $name: String!, ...any other thing that you want to send to server[backend] ) {
getUserDetails(email: $email, password: $password, ...any other thing that you
want to send to server[backend] ) {
id
name
email
}
}
`;
You can remove anything that you don’t want to be returned from you query