We have started using TSOA in our projects and found it extremely helpful -- so, here’s a big THANK YOU to the maintainers.
One major thing we’re currently missing is the ability to also send files instead of JSON responses (in our case, this could be (a) binary data, (b) exports such as CSV files).
There have been several requests and attempts on adding this in the past:
Unfortunately, both of the mentioned MRs are abandoned.
I have just rebased the more recent MR (#228) onto the current code base, and started to get a rough idea about the project structure. (see here)
Before I start investing a considerable amount of time, I would like to quickly clarify whether
Depending on this, I’ll try to get into it, try to address the open ends in the other MRs, and get back here with questions.
Many thanks for a feedback!
Hi,
Just to add here some of my findings from the last weeks where I somehow got some binary file download to work ... currently returning a file sort of works if you controller method return a Readable (stream) or a Buffer.
At least at runtime, you can properly download the file. Maybe the limitation at this point is mostly on how to reflect that information in the OpenApi spec file, unless I'm missing something.
Many thanks for the hint @tsimbalar -- this is in fact the same workaround which we currently use. With the suggestion above I’d especially like to cover the following two points:
Content-Type (currently this probably can be achieved through specMerging, but TSOA’s advantage is to have everything “in one place”)Readable, I still must declare the controller’s return type as Promise<any>, as I would get an error during route generation when using Promise<fs.ReadStream> insteadRegarding type-safety, I think there is currently no issue . I believe the following works fine :
import { Readable } from 'stream';
import * as fs from 'fs';
// more imports ...
@Get('directDownload')
public async directDownload(): Promise<Readable> {
const s = fs.createReadStream('');
return s;
}
i.e. what is returned from fs.createReadStream is a fs.ReadStream , but it conforms to the Readable interface from stream.
I may have misunderstood your comment though.
Interesting, I’ll definitely give this another try. Thank you!
[edit] I did another attempt following your suggestion @tsimbalar. The error which I encounter is in fact as follows:
Error: Multiple matching models found for referenced type ReadStream; please make model names unique. Conflicts found: "…/node_modules/@types/node/fs.d.ts"; "…/node_modules/@types/node/tty.d.ts".
I then tried ignoring the undesired interface via tsoa.json, by adding:
"ignore": ["**/node_modules/@types/node/tty.d.ts"]
However, this will give
There was a problem resolving type of 'ReadStream'.
Generate routes error.
TypeError: Cannot read property 'kind' of undefined
…
This issue is probably related to resolution strategy, as suggested here?
public async directDownload(): Promise<Readable> {
Please make sure you use this return type, not ReadStream.
E: Also, always a good idea to set the Content-Type/Disposition headers accordingly.
D’oh. I didn’t read properly, sorry! Indeed, when using Readable (NOT ReadStream), it works fine! Many thanks!
So, to get back to the initial post -- this MR would probably boil down to getting the generated OpenAPI specification right. Appreciate any feedback about this :-)
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days