Home > other >  Migrate GetObject (v2) to GetObjectCommand (v3) - aws-sdk
Migrate GetObject (v2) to GetObjectCommand (v3) - aws-sdk

Time:01-03

I'm trying to migrate an Express endpoint from v2 to v3 of the aws-sdk for JavaScript. The endpoint is a file downloader for AWS S3.

In version 2, I passed the result of GetObject back to the browser in a readable stream. In version 3 that same technique fails with the error:

TypeError: data.Body.createReadStream is not a function

How do I work with the data that returned from the new GetObjectCommand? Is it a blob? I'm struggling to find anything useful in the v3 SDK docs.

Here are the two versions of the endpoint:

import AWS from 'aws-sdk'
import dotenv from 'dotenv'

import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'

dotenv.config()

// VERSION 3 DOWNLOADER - FAILS
const getFileFromS3v3 = async (req, res) => {
  const client = new S3Client({ region: 'us-west-2' })
  const params = {
    Bucket: process.env.AWS_BUCKET,
    Key: 'Tired.pdf',
  }

  const command = new GetObjectCommand(params)

  try {
    const data = await client.send(command)
    console.log(data)
    data.Body.createReadStream().pipe(res)
  } catch (error) {
    console.log(error)
  } 
}

// VERSION 2 DOWNLOADER - WORKS
const getFileFromS3 = async (req, res) => {
  const filename = req.query.filename
  var s3 = new AWS.S3()
  var s3Params = {
    Bucket: process.env.AWS_BUCKET,
    Key: 'Tired.pdf',
  }

  // if the file header exists, stream the file to the response
  s3.headObject(s3Params, (err) => {
    if (err && err.code === 'NotFound') {
      console.log('File not found: '   filename)
    } else {
      s3.getObject(s3Params).createReadStream().pipe(res)
    }
  })
}

export { getFileFromS3, getFileFromS3v3 }

CodePudding user response:

This version 3 code works. Thanks to a major assist, the trick was to pipe data.Body and not use any of the fileStream methods.

import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'
import dotenv from 'dotenv'

dotenv.config()

const getFileFromS3 = async (req, res) => {
  const key = req.query.filename
  const client = new S3Client({ region: process.env.AWS_REGION })
  const params = {
    Bucket: process.env.AWS_BUCKET,
    Key: key,
  }

  const command = new GetObjectCommand(params)

  try {
    const data = await client.send(command)
    data.Body.pipe(res)
  } catch (error) {
    console.log(error)
  }
}

export { getFileFromS3 }

When called from this frontend function the code above returns the file from S3 to the browser.

  const downloadFile = async (filename) => {
    const options = {
      url: `/api/documents/?filename=${filename}`,
      method: 'get',
      responseType: 'blob',
    }

    try {
      const res = await axios(options)
      fileDownload(res.data, filename)
    } catch (error) {
      console.log(error)
    }
  }
  • Related