Can middleware be used to log the final HTTP response sent by Meteor?

A small part of your Meteor project are a handful of webhook URLs. Relatively simple endpoints that will be called by external systems with a (most often) HTTP POST request.

To make it easy for external parties to debug connections themselves, we want to be able to show the comings and goings of those URLs. Our idea was to create a middleware limited to the webhook endpoints where we would serialise and store both the IncomingMessage and ServerResponse.

But I got stuck trying to serialise the ServerResponse. OutgoingMessage is a Writable and it does not seem like I can setup a pipe or anything else to capture the response body.

Looking at different connect middleware the only one that seems to even dare touch the response body is Express’ compression. This seems to work by creating an entire proxy ServerResponse object to be able to intercept all writes.

I tried writing the simplest implementation of this that I could think of in a middleware, code below, but it is only logging gobbledygook.

Has anyone tried to capture the response from Meteor in as late a state as possible? Any tips?

The reason we are looking at doing it this way is because different parts of the full request handling might throw a Meteor.Error along the way. We want to log as close to reality as possible: what exactly did Meteor end up sending to the requestor. Not just log what we think the response body from our inner function would be.

The failing proof-of-concept:

export const middleware: NextHandleFunction = (req, res, next) => {
    const _write = res.write;
    res.write = (...args) => {
      console.log(args[0].toString("utf8"));
      return _write.apply(res, args);
    };
    next();
};

Another thing I was thinking about: maybe what I describe as gobbledygook could actually be gzip compressed output? Is it possible to insert my middleware at a step before Meteor adds this? Even Meteor.startup() seems too late, e.g.:

Meteor.startup(() => {
    WebApp.rawConnectHandlers.use(middleware);
});

We are doing this as we are serving AMP versions of pages in one project. And we have to hack on multiple packages, especially, webapp to catch the output and run it through our AMP boilerplate.

It wasn’t pretty as we have to maintain our fork getting upstream changes when the package is updated. We still don’t have time to figure out how to elegantly make this into a “middleware”

Have you made these changes available anywhere? It would be great to get some indicators of where I might be looking for this. I too would prefer not to have to hack away on the core WebApp, but if that is what it takes …

Rather than a full fork, depending on how involved the changes are, I could see putting some time into maintaining it as a set of patches (possibly through something like patch-package). That might make it easier to keep it updated to the main Meteor.

But I say that only thinking my use-case might be a little more “lite” than yours. As we do not need to do anything transformative with it.

It’s in our private repo in gitlab.