Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NestJS return a fie from GridFS

I am trying to return a file from GridFS using my Nest controller. As far as I can tell nest is not respecting my custom content-type header which i set to application/zip, as I am receiving a text content type upon return (see screenshot).

response data image, wrong content-type header

My nest controller looks like this

  @Get(':owner/:name/v/:version/download')
  @Header('Content-Type', 'application/zip')
  async downloadByVersion(@Param('owner') owner: string, @Param('name') name: string, @Param('version') version: string, @Res() res): Promise<any> {
    let bundleData = await this.service.getSwimbundleByVersion(owner, name, version);
    let downloadFile = await this.service.downloadSwimbundle(bundleData['meta']['fileData']['_id']);   
    return res.pipe(downloadFile);
  }

Here is the service call

downloadSwimbundle(fileId: string): Promise<GridFSBucketReadStream> {
      return this.repository.getFile(fileId)
    }

which is essentially a pass-through to this.

  async getFile(fileId: string): Promise<GridFSBucketReadStream> {
    const db = await this.dbSource.db;
    const bucket = new GridFSBucket(db, { bucketName: this.collectionName });
    const downloadStream = bucket.openDownloadStream(new ObjectID(fileId));

    return new Promise<GridFSBucketReadStream>(resolve => {
        resolve(downloadStream)
      });
  }

My end goal is to call the download endpoint and have a browser register that it is a zip file and download it instead of seeing the binary in the browser. Any guidance on what needs to be done to get there would be greatly appreciated. Thanks for reading

like image 602
feralamerican Avatar asked Mar 05 '23 13:03

feralamerican


1 Answers

You also need to set the Content-Disposition header with a file name. You can use the @Header() decorator if the file name will always be the same or setHeader directly on the response object if you need to be able to send back different file names based on some parameter in your controller.

Both of the following example controller methods work for sending back a downloadable file to the browser from my local file system.

@Get('/test')
@Header('Content-Type', 'application/pdf')
@Header('Content-Disposition', 'attachment; filename=something.pdf')
getTest(@Res() response: Response) {
   const data = createReadStream(path.join(__dirname, 'test.pdf'));
   data.pipe(response);
}

@Get('/test')
@Header('Content-Type', 'application/pdf')
getTest(@Res() response: Response) {
   const data = createReadStream(path.join(__dirname, 'test.pdf'));

   response.setHeader(
     'Content-Disposition',
     'attachment; filename=another.pdf',
   );

   data.pipe(response);
}
like image 121
Jesse Carter Avatar answered Mar 08 '23 21:03

Jesse Carter