Skip to content
Advertisement

QuerySnapshot.empty causes a promise rejection error

I have a back-end using firebase-admin and express to allow post requests from the client to the server to make changes to the firestore I have that contains stuff like user data (this is a test and not a real product). I want to check if a document already exists so a user cannot register with that username again. I have first seen instances of doc.exists but that returns undefined for me and I looked into the documentation and found doc.empty which is said to check if a document is empty. I tried it but it returned a promise rejection error. If I changed that line to .exists or to something else, that goes away so I have narrowed down the issue to that line.

index.js (backend)

app.post("/registeruser", function (req, res) {
    res.setHeader("Content-Type", "application/json");

    try {
        const username = req.body.username;
        const password = req.body.password;
        const passwordEncrypted = HmacSHA1(password, JSON.parse(fs.readFileSync("./keys.json"))["passwordEncryptKey"]).toString();

        // console.log(username, password, passwordEncrypted);

        try {
            firestore.collection("users").get(username).then(function (data) {
                if (data.empty == false) {
                    throw [true, "Already registered user!"];
                }
            }).catch(function (error) {
                throw [true, error];
            });

            if (username == "") {
                firestore.collection("users").add({
                    username: v4(),
                    passwordhash: passwordEncrypted,
                    email: "example@gmail.com",
                }).then(function () {
                    return res.status(200).send(JSON.stringify({
                        error: false,
                        message: "Successfully registered user!",
                    }))
                }).catch(function (error) {
                    throw [true, error];
                });
            }
            else {
                firestore.collection("users").doc(username).set({
                    username: username,
                    passwordhash: passwordEncrypted,
                    email: "example@gmail.com",
                }).then(function () {
                    return res.status(200).send(JSON.stringify({
                        error: false,
                        message: "Successfully registered user!",
                    }));
                }).catch(function (error) {
                    throw [true, error];
                });
            }
        }
        catch (error) {
            throw [true, error];
        }
    }
    catch (error) {
        console.log(error);
        const [isError, errorMessage] = error;

        return res.status(404).send(JSON.stringify({
            error: isError,
            message: errorMessage,
        }));
    }
});

Terminal Output

(node:29448) UnhandledPromiseRejectionWarning: [object Array] (node:29448) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:29448) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Advertisement

Answer

You have multiple concurrent promise chains, and some of those can fail independently. You need to consolidate all your logic into one promise chain.

return firestore.collection("users").get(username)
  .then((data) => {
    if (data.empty == false) {
      throw [true, "Already registered user!"];
    }
  })
  .then(() => {
    if (username == '') {
      return firestore.collection("users").add({/* Your data */});
    }

    return firestore.collection("users").doc(username).set({/* Your data */});
  })
  .then(() => {
    return res.status(200);
  })
  .catch((err) => {
    return res.status(500);
  });

You can also try using async/await which will significantly simplify logic like this.

Advertisement