Search code examples
javascriptnode.jsexpressamazon-s3multer

express.js: pass an uploaded image to s3


I am trying to pass an image uploaded from a react app through express to a managed s3 bucket. The platform/host I am using creates and manages the s3 bucket and generates upload and access urls. This all works fine (I have tested a generated upload url in postman with an image in a binary body and it worked perfectly).

My problem is passing the image through express. I am using multer to get the image from the form but I am assuming multer is turning that image into some kind of file object and s3 is expecting some sort of blob or stream.

In following code, the image in req.file exists, I get a 200 response from s3 with no errors and when I visit the asset url the url works, but the image itself is missing.

const router = Router();
const upload = multer()

router.post('/', upload.single('file'), async (req, res) => {
    console.log(req.file)
    const asset = req.file
    const assetPath = req.headers['asset-path']

    let s3URLs = await getPresignedURLS(assetPath)
  
    const sendAsset = await fetch(
      s3URLs.urls[0].upload_url, // the s3 upload url 
      {
        method: 'PUT',
        headers: {
            "Content-Type": asset.mimetype
        },
        body: asset,
        redirect: 'follow'
      }
    )
  console.log("s3 response", sendAsset)

  res.status(200).json({"url": s3URLs.urls[0].access_url });
  
});

export default router;

I am not sure what to do to convert what multer gives me to something that aws s3 will accept. I am also open to getting rid of multer if there is an easier way to upload binary files to express.


Solution

  • For anyone that ever stumbles across this question the solution was to create an custom multer storage engine. Inside the engine you get access to the file with a stream property that s3 accepted (with the correct headers).