cancel
Showing results for 
Search instead for 
Did you mean: 

Error when returning zip file from cap

0 Kudos

Hello Experts,

In my project I am trying to return a .zip file (filled with multiple csv/xlsx/json documents) from an odata function. To do this I am accessing the underlying express response object and piping the generated zip file as a readable stream. When I do this in a pure express app it works fine, but when doing it through cap the file gets corrupted and I am unable to open it once downloaded. A full example repo is available here, below are the important parts:

//The function I am using to pip the zip file, res is the express response object.
// Definition is found in express/app.js in repo 
const loadResponse = async (res, type) => { 
  const content = await getZip(type); 
  res.set('Content-Type', 'application/zip'); 
  res.set('Content-Disposition', 'attachment; filename="myfile.zip"');
  
  const stream = new Readable(); 
  stream.push(content); 
  stream.push(null);

  stream.pipe(res); 

  // Await stream finish before returning
  await new Promise((resolve, reject) => { 
    stream.on('end', resolve); 
    stream.on('error', err => reject(err)); 
  });
}


// Three different implementations of the function above
// 1. Called from pure express app (in express/app.js)

app.get('/getCsv', async (req, res) => { 
  await loadResponse(res, 'csv'); // This works
});

// 2. Called from custom route on server start (server.js)
cds.once('bootstrap', app => { 
  app.get('/getZip', async function(req, res, next) { 
    await loadResponse(res, 'csv'); // Returns invalid file 
  });
});

// 3. Called from service handler function (srv/my-service.js)
srv.on('getZip', async req => { 
  await loadResponse(req.context.http.res, 'csv'); // Returns invalid file 
});

Of the three examples above, the one when running a pure express app (number 1) returns the zip-file correctly, whereas both of the cap implementations return an invalid zip file that can't be opened. Any input as to why this might be would be much appreciated.

Best Regards,

Jibbril

Accepted Solutions (0)

Answers (1)

Answers (1)

vitaly_kozyura
Participant
0 Kudos

Hi Jibbril, The res object in CAP is not the express res object. You can do custom streaming like here. Best regards, Vitaly

0 Kudos

Hello Vitaly,

I did try that approach as well but was unable to get it to work unless I was targeting a specific object. So something like "/MyEntity(abc123)/myZip" would work, but "/MyEntity/myZip" would not work. I don't want to target a specific entity like that, but access a more general endpoint that gathers several entities (depending on passed parameters) and bundles them in a zip, so using a function instead of an on read handler seems like the right approach no?

Best Regards,

Jibbril