Jasper
Jasper

Reputation: 2409

return value of a firebase callable function

I have difficulties returning a value using a callable firebase function, while the same code works fine when it is a httprequest.

So what I am doing, is getting some user data, then getting some other data (a list of vessels) and then only return the vessels the user has edit rights for. I am very sure the accessibleVessels object holds some json data: I changed the function in a functions.https.onRequest firebase function and it went fine.

exports.getFormData = functions.https.onCall( (data, context) => {
  const uid = context.auth?.uid.toString;
  try {
    const user = admin.firestore().
        doc("users/"+uid)
        .get().then((doc: any) => {
          return doc.data();
        });

    const vessels = admin.firestore().
        collection("vessels").get()
        .then(mapSnapshot((doc: any) => doc.data()));

    const accessibleVessels = vessels.filter((vessel: any) => {
      return user.hasEditRights.some((right: any) => {
        return vessel.name === right;
      });
    });


    return accessibleVessels;
  } catch (error) {
    console.log(error);
    return {"error": true};
  }
});

When I run this I get:

Data cannot be encoded in JSON. [Function (anonymous)]

Looking in the documentation I understand that I do need to return json or a promise. I read other answers about this (returning a promise) but don't see how this would work in my example: in the examples I find not much is done with the data, it's just returned. I want to put the data in variables instead of chaining everything, so I can combine both. How should I do this?

Upvotes: 1

Views: 1322

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 600126

The easiest way to fix this is using async/await:

exports.getFormData = functions.https.onCall(async(data, context) => { // 👈
  const uid = context.auth?.uid.toString;
  try {
    const user = await admin.firestore() // 👈
        .doc("users/"+uid)
        .get().then((doc: any) => {
          return doc.data();
        });

    const vessels = await admin.firestore() // 👈
        .collection("vessels").get()
        .then(mapSnapshot((doc: any) => doc.data()));

    const accessibleVessels = vessels.filter((vessel: any) => {
      return user.hasEditRights.some((right: any) => {
        return vessel.name === right;
      });
    });


    return accessibleVessels;
  } catch (error) {
    console.log(error);
    return {"error": true};
  }
});

I also recommend reading the MDN documentation on async/await, the Firebase documentation on sync, async, and promises and Doug's awesome series on JavaScript Promises in Cloud Functions.

Upvotes: 1

Related Questions