1

So I'm trying to take a file used as a starting template, add data to it in the stream (not altering original file), and serve it to the client without saving a new file on the server (I'm currently using the express module as well).

So far I pass the data in a post request add add it to the end of the stream. Unfortunately when you pipe the read stream to a write stream you have to specify the output file and location for the write stream. Is there any way around that? Can you set the output file location as the relevant port?

This is what I currently have (getting error: Cannot pipe, not readable):

app.post("/output_xml", function(req, res) {
    var data = validateJSON(req.body);
    stream_xml(data, res);
});

function stream_xml(data, res)
{
    var read_stream = fs.createReadStream(__dirname + '/Static/input_template.xml')
    var write_stream = fs.createWriteStream(__dirname + '/Static/output.xml') // trying to prevent saving a file to the server though
    read_stream.pipe(write_stream);

    read_stream.on('end', () => {
        write_stream.write(data);
        write_stream.write("\nAdding more stuff");
    });

    write_stream.pipe(res);
} 

Would I be able to swap the write_stream line for anything like:

var write_stream = fs.createWriteStream('http://localhost:3000/output_xml/output.xml')
Mick
  • 413
  • 4
  • 14

1 Answers1

1

You cannot pipe from a write stream, but you can certainly pipe from a transform/duplex stream.

So you can do something like:

const { Transform } = require('stream');

const custom_response = new Transform({
    transform(chunk, encoding, callback) {
        this.push(chunk, encoding);
        callback();
    },

    flush(callback) {
        this.push(data);
        this.push("\nAdding more stuff");
        callback();
    },
});

read_stream.pipe(custom_response).pipe(res);

An alternative to stream.Transform may also be stream.PassThrough which takes the same parameters as Transform, but you only need to specify the flush method.

https://nodejs.org/api/stream.html#stream_implementing_a_transform_stream

smac89
  • 39,374
  • 15
  • 132
  • 179
  • Thanks! and how do I handle that app.post, should I be using res.sendFile or res.download? – Mick Dec 01 '18 at 05:24
  • @Mick think you can do the same thing this person did: https://stackoverflow.com/a/18857838/2089675. So basically you don't need to do anything because the res will stream everything and close the stream once it is finished. – smac89 Dec 01 '18 at 07:57