File request piping in smart actions

I have an endpoint which streams a csv as a response. It’s not from a file but a direct DB => Format => Append to Stream process. Here is how it is written:

try {
    const datetime = new Date();
    res.set('Expires', dateTime);
    res.set('Cache-Control', 'max-age=0, no-cache, must-revalidate, proxy-revalidate');
    res.set('Last-Modified', `${datetime} GMT`);
    res.set('Content-Type', 'application/octet-stream');
    res.set('Content-Disposition', 'attachment;filename=Data.csv');
    res.set('Content-Transfer-Encoding', 'binary');

    res.write(objectToCSV(headers));

    for (const dateChunk of dateChunks) {
      const rawData = await getData(dateChunk.from, dateChunk.to);

      // Skip if empty
      if (!data.length) continue;

      // Stream it
      res.write(`\n${objectArrayToCSV(rawData)}`);
    }
    res.end();
  } catch (error) {
    logger.error('Export made error', { error });
    throw new Error('EXPORT_FAILURE');
  }

The endpoint works wonder and streams the csv as a download in the browser.

But now I want to configure it as a Smart Action. This means that I have to handle the request through a Forest Admin endpoint.

Liana.collection('myCollection', {
  actions: [
    {
      name: 'Export CSV',
      fields: [{ field: 'fromDate', type: 'Dateonly' }, { field: 'toDate', type: 'Dateonly' }],
      type: 'global',
      download: true,
    },
  ],
});
static exportDataCSV(req, res) {
    const fromDate = req.body.data.attributes.values.fromDate;
    const toDate = req.body.data.attributes.values.toDate;

    api.exportDataCSV(fromDate, toDate).then(apiRes => {
      res.status(200);
      res.set({
        'Access-Control-Expose-Headers': 'Content-Disposition',
        'Content-Disposition': `attachment; filename="data.csv"`,
        'Content-Type': 'text/csv; charset=utf-8',
      });
      apiRes.data.pipe(res);
    });
  }

The file download doesn’t stream, it freezes, waits for the entire file to be downloaded and outputs it with the wrong filename.

Please note that the following works as intended, it’s the same without the Forest Admin layer:

const express = require('express');
const axios = require('axios');
const app = express();
const port = 3008;

app.get('/test', async (req, res) => {
  const apiRes = await axios.get('http://localhost:3000/myData/exportCSV?fromDate=2018-01-01&toDate=2020-05-01', {
    responseType: 'stream',
  });
  res.status(200);
  res.set({
    'Content-Disposition': `attachment; filename="data.csv"`,
    'Content-Type': 'text/csv; charset=utf-8',
  });
  apiRes.data.pipe(res);
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});
  • Package Version: 10.22.0
  • Express Version:

Hi @yleflour,

Welcome to our community and thanks for sharing your issue!

You’re right about the fact that the file is outputting only at the end of the download. We could improve that in the future, I am going to create a feature request in our Product roadmap.

About the wrong name, it is strange. Do you have any error in your console that could help us investigate?

Thanks!

@anon34731316 Seems that I’m mistaken regarding the name, I think I had forgotten Access-Control-Expose-Headers at first.

Do you know by any chance if it’s a frontend or backend issue ?

Ok great, the file name is correct then when you put 'Access-Control-Expose-Headers': 'Content-Disposition'?
(I am not sure what you’re referring when talking about frontend or backend issue :roll_eyes: )