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.
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?
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 ?
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.
I'm not positive, but I see a few things that might be causing this.
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.
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);
});
}