I'm trying to work with class-transformer and NestJS. I'm building an API based on Mongoose and GraphQL. This is how I'm using Exclude decorator in one of my GraphQL objects:
@ObjectType('user')
export class User extends Teacher {
@Field()
login: string;
@Field()
@Exclude()
password: string;
}
And this is my method in UserResolver used with ClassSerializerInterceptor:
@UseInterceptors(ClassSerializerInterceptor)
@Mutation(returns => User, { name: 'editUserById', nullable: true })
async editById(
@Args('id') id: string,
@Args({ name: "item", type: () => UserInputType }) item: UserInputType
) {
const user = await this.usersService.editById(id, item);
return user;
}
What I'm trying to do is to get from this mutation user fields without a password (which is excluded in GraphQL object). But unfortunately, all fields are null. Error example from GraphQL playground:
{
"errors": [
{
"message": "Cannot return null for non-nullable field user.firstName.",
"locations": [
{
"line": 3,
"column": 5
}
],
"path": [
"editUserById",
"firstName"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR"
}
}
],
"data": {
"editUserById": null
}
}
Teacher object:
@ObjectType('teacher')
@InputType()
export class Teacher {
@Field()
_id: string;
@Field()
firstName: string;
@Field()
lastName: string;
@Field(type => [String], { nullable: true })
schoolsIds: string[];
@Field(type => [School], { nullable: true })
schools: School[];
}
Without interceptor, everything is working fine (except that password is still visible). Any ideas what I'm doing wrong?
You've told GraphQL you will be returning a User
object which has the non-nullable field password
on it. You've also told class-transformer
that when plainToClass
is ran, the password
field must be removed. So now GraphQL is upset because you've broken the object contract you've said should be there (the returned object must have a password
field) because you've told another library to remove that field.
You have a few options here:
use @Field({ nullable: true })
to tell GraphQL this field doesn't have to be returned. This does still mean that someone can query for that field and it will always be undefined
though
Remove the password
@Field()
annotation because it should not be returned on a user
query and only keep it on the @InputType()
object.
Thanks for an answer from the comments of this answer, you're returning an object from the database instead of an instance of the User
class. If what your database returns have class-transformer decorators you'll want to check what could be happening there (such as possibly excluding fields). Also, note that returning mongoose objects does have some problems with class-transformer directly, and you may need to transform the database return to a plain JSON and then to a class for class-transformer
to properly work