Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

NestJS problem with ClassSerializerInterceptor in GraphQL

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?

question from:https://stackoverflow.com/questions/65647447/nestjs-problem-with-classserializerinterceptor-in-graphql

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

  1. 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

  2. Remove the password @Field() annotation because it should not be returned on a user query and only keep it on the @InputType() object.

Edit

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...