how to resolve async s3 resolver upload on nodejs + graphql?

Viewed 246

what i want to do is upload the image first the save the link to a user in db.

This is my graphql resolver:

resolve: async (_root, args, { user, prisma }) => {

        ....

        const params = {
          Bucket: s3BucketName,
          Key: fileName,
          ACL: 'public-read',
          Body: file.createReadStream(),
          ContentType: file.mimetype,
        };
        return s3.putObject(params, async function (error, data) {
          if (error) {
            return {
              message: error,
              success: false,
            };
          } else {
            // user has updated
            if (user.profileImg)
              return prisma.user
                .update({
                  where: { id: Number(user.id) },
                  data: {
                    profileImg: fileName,
                  },
                })
                .then(
                  (response) => {
                    console.log('response: ', response);
                    return {
                      message: 'Success',
                      success: true,
                    };
                  },
                  (error) => {
                    return {
                      message: error,
                      success: false,
                    };
                  }
                );
            else {
              return {
                message: 'Success',
                success: true,
              };
            }
          }
        });
      },

what i want to do is return from s3, but my problem is i think it returns without this resolving and returns null so emmage and success is not returned. how do i construct a function resolver using s3?

1 Answers

You should return new Promise from your resolver, instead of making it async this way you can explicitly resolve() or reject() from within the nested callback.

resolve: (_root, args, { user, prisma }) => {
  return new Promise((resolve, reject) => {
    s3.putObject(params, async (error, data) => {

      if (error) {
        return reject({
          message: error.message,
          success: false
        });
      }

      try {
        await prisma.user.update();

        return resolve({
          message: "Success",
          success: true
        });
      } catch (e) {
        return reject({
          message: e.message,
          success: false
        });
      }

    });
  });
};

If you wanted to stay in the async/await paradigm, make a utility/promise-wrapper around s3.putObject;

function putObject(...params) {
  return new Promise((resolve, reject) => {
    s3.putObject(...params, async (error, data) => {
      if (error) {
        return reject(error);
      }

      return resolve(data);
    });
  });
}

resolve: async (_root, args, { user, prisma }) => {
  try {
    const response = await putObject(params);

    await prisma.user.update();

    return {
      message: "Success",
      success: true
    };
  } catch (error) {
    return {
      message: error.message,
      success: false
    };
  }
};
Related