Adam Richardson

Uploading Images to Amazon S3 using a Next.js API route and React

Adam Richardson /

This code snippet is using a pre-signed URL to upload an image to AWS, and push the link into a DB using Prisma.

Backend API route code

/api/awsimageupload.js
import { NextApiRequest, NextApiResponse } from "next";
import prisma from "../../client";
import { getSession } from "next-auth/client";
import aws from "aws-sdk";

export default async function (req: NextApiRequest, res: NextApiResponse) {
  const session = await getSession({ req });

  aws.config.update({
    region: "eu-west-2",
    accessKeyId: process.env.AWS_ACCESS_KEYY,
    secretAccessKey: process.env.AWS_SECRETT
  });

  const s3Bucket = process.env.AWS_BUCKET;

  const s3 = new aws.S3(); // Create a new instance of S3
  const fileName = req.body.fileName;
  const fileType = req.body.fileType;

  console.log(fileName);
  console.log(fileType);

  const s3Params = {
    Bucket: s3Bucket,
    Key: `businesslogos/${fileName}`,
    ContentType: fileType,
    ACL: "public-read"
  };

  try {
    s3.getSignedUrl("putObject", s3Params, async (err, data) => {
      if (err) {
        return res.json({ success: false, error: err });
      }
      const returnData = {
        signedRequest: data,
        url: `https://${s3Bucket}.s3.amazonaws.com/businesslogos/${fileName}`
      };
      const imageUrl = await prisma.user.update({
        where: {
          email: session.user.email
        },
        data: {
          business: {
            update: {
              businessLogo: returnData.url
            }
          }
        }
      });

      return res.status(200).json(returnData);
    });
  } catch (err) {
    return res.status(500).json(err);
  }
}

Frontend Code

/components/UploadLogo.tsx
const handleUpload = ev => {
let file = uploadInput.current.files[0];
// Split the filename to get the name and type
let fileParts = uploadInput.current.files[0].name.split(".");
let fileName = fileParts[0];
let fileType = fileParts[1];
axios
  .post("/api/awsimageupload", {
    fileName: fileName,
    fileType: fileType
  })
  .then(res => {
    const signedRequest = res.data.signedRequest;
    const url = res.data.url;
    setUploadState({
      ...uploadState,
      url
    });

    var options = {
      headers: {
        "Content-Type": fileType
      }
    };
    axios
      .put(signedRequest, file, options)
      .then(_ => {
        setUploadState({ ...uploadState, success: true });
        mutate();
      })
      .catch(_ => {
        toast("error", "We could not upload your image");
      });
  })
  .catch(error => {
    toast("error", "We could not upload your image");
  });
};

© 2021 Adam Richardson. All rights reserved.