Ahmed Elsayes
Ahmed Elsayes

Reputation: 131

Download readable image from AWS s3 using an API route in Nextjs

I am using Nextjs to build my app. I am using AWS s3 to store my static files (images and PDFs,..)

I want user of my application to be able to download the file. I used the answer mentioned here to develop a solution and it worked but the image is not readable. It shows

It appears that we don't support this file format

Here is my script:

// /pages/api/getFile.js
import { NextApiRequest, NextApiResponse } from "next";
import stream from 'stream';
import { promisify } from 'util';
import s3 from "../../../../utils/s3-utils";
const pipeline = promisify(stream.pipeline);

export default async (req: NextApiRequest, res: NextApiResponse) => {
  const bucketName = process.env.S3_UPLOAD_BUCKET || ""

  const imageKey: any = req.query.imgkey

  const downloadParams = {
    Key: imageKey,
    Bucket: bucketName
  }

  const downloadedObject = await s3.getObject(downloadParams).promise()
  const readableFile= downloadedObject.Body?.toString('base64') || ""
  const fileType= downloadedObject.ContentType || ''

  res.setHeader('Content-Type', fileType);
  res.setHeader('Content-Disposition', `attachment; filename=${imageKey}`);
  await pipeline(readableFile, res);
}

from client:

<a href="/api/getFile">Download PDF</a>

Any idea what is the wrong here?

Upvotes: 2

Views: 5479

Answers (1)

Ahmed Elsayes
Ahmed Elsayes

Reputation: 131

Here is the answer: I was able to simply solve it by using createReadStream() and piping the response stream with using the proper response header

import s3 from "../../../../utils/s3-utils";

export default async (req: NextApiRequest, res: NextApiResponse) => {
  const bucketName = process.env.S3_UPLOAD_BUCKET || ""
  const imageKey: string = req.query.imgkey.toString()
  const imageFormat = imageKey.split(".")[1]

  const downloadParams = {
    Key: imageKey,
    Bucket: bucketName
  }

  const readableObject = s3.getObject(downloadParams).createReadStream()

  res.setHeader('Content-Type', `image/${imageFormat}`);
  res.setHeader('Content-Disposition', `attachment; filename=${imageKey}`);
  readableObject.pipe(res)
}

Upvotes: 5

Related Questions