on 01-20-2023 1:16 PM
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
Hi Jibbril, The res object in CAP is not the express res object. You can do custom streaming like here. Best regards, Vitaly
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
User | Count |
---|---|
86 | |
10 | |
10 | |
9 | |
7 | |
7 | |
6 | |
5 | |
4 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.