Search code examples
typescriptbcrypttypeormtypegraphql

Cannot return null for non-nullable field Mutation.create in typegraphql with bcrypt


I am trying typegraphql with apollo-server, typeorm, bcrypt with the below resolver in typescript. When the mutation query is run it throws the error 'Cannot return null for non-nullable field Mutation.create'. But it is saving the data to database with hashed password (also i can infer this for sure by using console.log); Only the mutation query is throwing error in browser.

Here is mutation resolver:

@Mutation(returns => Users)
create(@Arg("newuser") newuser: UserInput): Promise<Users> | any {
  bcrypt.hash(newuser.loginpassword, 12)
  .then( hash => {
      const new_user = this.usersRepository.create(newuser);
      new_user.loginpassword = hash;
      return this.usersRepository.save(new_user);
    });
}

Same when bcrypt related stuff is commented out like below, returns no errors (of-course the password is not hashed)

@Mutation(returns => Users)
create(@Arg("newuser") newuser: UserInput): Promise<Users> | any {
  // bcrypt.hash(newuser.loginpassword, 12)
  // .then( hash => {
      const new_user = this.usersRepository.create(newuser);
      //new_user.loginpassword = hash;
      return this.usersRepository.save(new_user);
    //});
}

In both the cases, mutation is able to create the record and save them; Also hash is successfully generated with bcrypt code.

I am trying to solve this for last 2 weeks, searching here (Graphql, node.js and sql,Cannot return null for non-nullable field and many similar) for clues to solve this.

  1. What is wrong in first version (that is with bcrypt code included) I have tried changing the return type to Users | any from Promise | any, and adding one more .then statement returning the Users object instead of promise object?

  2. Also in Graphql, node.js and sql,Cannot return null for non-nullable field, Mr. Benjie is hinting at https://www.graphile.org/postgraphile/why-nullable/#nulls-in-graphql. But I am absolutely clueless how to write nullable Mutation.create. Can someone hint or point to an example or such pattern, pls ?

  3. If I keep the create's return declaration to 'Promise<Users>' instead of 'Promise<Users> | any', typescript is not happy and is expecting a return statement. But if I add return statement at the end, create will simply return immediately. So, is the return declaration as 'Promise<Users> | any' is the proper way?

Thank you all.


Solution

  • I'm not positive, but I see a few things that might be causing this.

    1. In your first code snippet, the only return statement is inside the callback function passed to then. So the create method does not return anything.

    2. I looked at the src for typeORM... it looks like Repository.save() returns Promise<Entity> (not Promise<Entity[]>) when the input value is a single entity object (see Repository.ts). If this is the case, your GraphQL schema would be expecting this mutation to return an array of users, but the resolver is returning a single user.

    Try changing the return type to Promise<User>

    @Mutation(returns => User)
    create(@Arg("newuser") newuser: UserInput): Promise<User> {
      return bcrypt.hash(newuser.loginpassword, 12)
      .then( hash => {
          const new_user = this.usersRepository.create(newuser);
          new_user.loginpassword = hash;
          return this.usersRepository.save(new_user);
        });
    }