I am writing a resolver for a typical updateUser
mutation with node, Apollo Server and mongoDB. I want to make it such that, when the email
input is provided, it will update the email; when the password
input is provided, it will hash and then update the password; and when the plan
input is provided, it will update the plan - but I only want the compulsory field when calling the mutation at the front-end to be id
(and at least one of email, password or plan).
Here is my code:
export const updateUser = async (
_: undefined,
{ input: { id, email, password, plan } }: any
): Promise<any> => {
const collection = getCollection(USERS_COLLECTION_NAME);
try {
const updateWith = (() => {
const toUpdate: any = {};
if (email) toUpdate['email'] = email;
if (password)
toUpdate['hashedPassword'] = (async () =>
await bcrypt.hash(password, 10))();
if (plan) toUpdate['plan'] = plan;
return toUpdate;
})();
const updateResult = await collection.findOneAndUpdate(
{
_id: new mongodb.ObjectId(id), // new mongodb.ObjectId needed, otherwide null; converts to BSON
},
{
$set: updateWith,
},
{ returnDocument: 'after' } // returns updated user rather than user before updates
);
if (!updateResult?.value) {
throw new HttpError(500, 'Could not update user');
}
// note: it updates the user even if the value provided is the same as the existing value
return updateResult.value;
} catch (error: any) {
throw new HttpError(error.statusCode, error.message);
}
};
It would be great to get some feedback and become a better developer, hence I have a few questions:
- Could the
updateWith
function be improved? - Is it correct to add another try-catch block inside the inner async function (near
if (password)
), despite there being an outer one? - Is it bad practice to have one resolver to update multiple fields rather than creating separate resolvers for each field (e.g. a mutation for changeUserEmail, changeUserPlan, changeUserPassword, etc)? The code has to run many if statements, so I’m wondering whether it’s using unnecessary bandwidth
- What should the type be for error in the catch block, rather than
any
? - Should
updateWith
be outside the try block?
Thanks for any advice.