W. Bright
W. Bright

Reputation: 113

How to create an onSnapshot listener using firestore and express.js

I am trying to set up real-time functionality by adding an onSnapshot listener to a document. It works fine when I call the api, but whenever I modify the data I get hit with a

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

function routes() {
  const router = express.Router();

  router.route("/jobs/:company").get(async (req, res) => {
      const company = req.params.company;

      const snapshot = db
        .collection("companies")
        .doc(company)
        .collection("operations")
        .doc("jobs")

        snapshot.onSnapshot(docSnapshot=> {
          res.status(200).send(docSnapshot.data());
        }, err => {
          res.status(500).send(err)
        });

  });
}

I know this sort of error occurs when you call res.send(something) multiple times, but it's not the case here. Meanwhile, I checked my firebase node module and noticed the reference.js file calling an onNext function that might be triggering the error. I am not really sure what's going on here but I would really appreciate some help.

Upvotes: 0

Views: 1930

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317372

onSnapshot() attaches a persistent listener that will keep getting invoked for every change to the document. That's why send() is getting called more than once. Express doesn't allow this because it must send an entire response at once over the HTTP connection.

Instead, you should be using get() to fetch data a single time as illustrated in the documentation. There's no need for a persistent listener here.

      const ref = db
        .collection("companies")
        .doc(company)
        .collection("operations")
        .doc("jobs")

      ref.get()
      .then(docSnapshot=> {
        res.status(200).send(docSnapshot.data());
      })
      .catch(err => {
        res.status(500).send(err)
      });

If you are actually trying to send multiple document updates to the client over an HTTP connection, you're going to have to look into sending a chunked HTTP encoded response, and making sure both your server and client frameworks can actually work with that HTTP protocol detail. It might be more trouble than it's worth (in which case, you should probably have the client just use the Firestore SDK directly).

Upvotes: 3

Related Questions