Image Uploader with NextJS and AntD

2021-04-02

Challenge

File uploads is a common component required for majority of web applications. This article will be a brief tutorial on putting together an image uploader in NextJS using its serverless functions to process the incoming files. On the frontend we'll use AntDs React UI library and the Upload component.

Preparing the serverless function

We will create a serverless function with the api route name upload .

Install required packages

Create upload.js in the pages\api folder to create the route

Lets set up the structure of the file

By default, NextJS serverless functions have built-in middleware to process incoming requests to provide the following methods on the request object.

Since we will be sending files via FormData, we will not want the content of the request to be parsed by the default middleware bodyParser , but instead by another package called Multer which enables us to handle the multi-part FormData.

To do this we can configure NextJS serverless functions by exporting a config object.

https://nextjs.org/docs/api-routes/api-middlewares#custom-config

export const config = {
  api: {
    bodyParser: false,
  },
};

Configure Multer

We can now take the unparsed request object and put it through the Multer middleware. To use Multer though, we will need to configure it.

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "./public/uploads");
  },
  filename: (req, file, cb) => {
    const { originalname } = file;
    cb(null, originalname);
  },
});

const upload = multer({ storage });

Set up middleware

First we'll borrow the NextJS example helper function called runMiddleware to help clean up the code.

function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) {
        return reject(result);
      }
      return resolve(result);
    });
  });
}

This function takes the req , res and a third item, the custom middleware function, fn . It returns a new Promise and just simply executes the fn , but with a callback function to resolve or reject the Promise once the middleware function is completed.

This makes it pretty easy to tack on other compatible Express or Connect type middleware packages and pipe them into the api function.

Lets use this helper function now to setup Multer. We will convert the api function to an async function and await the execution of the middleware functions.

export default async (req, res) => {
  await runMiddleware(req, res, upload.array("files"));
 
  res.status("200").json({
    success: true,
		payload: "File Uploaded"
  });
};

upload.array("files") - the .array("files") is used to handle an array (multiple) of files. We pass in the first parameter a string with the value "files" to identify the expected field name of the FormData with the files.

What about CORS?

We aren't planning to access this api endpoint from outside of our domain. But, if we were going to we would have to mange the cors for this function.

Setting up the client side upload component

We will be taking advantage of the already styled and configurable Upload component from the AntD component library. Create a UploadComponent.js component file in your component library and import Upload , Button , UploadOutlined , om the respective libraries.

import { Upload, Button } from "antd";
import { UploadOutlined } from "@ant-design/icons";

export default function UploadComponent() {  
  return (
    <>
      <Upload
        action="/api/upload"
        listType="picture"
        defaultFileList={[]}
        name="files"
				multiple={true}
      >
        <Button icon={<UploadOutlined />}>Upload</Button>
      </Upload>
    </>
  );
}

Simply render the Upload component and pass the desired prop configurations that is available from the Upload component api ( https://ant.design/components/upload/#API ). The action prop value is set to our NextJS api route that we just created. Also note that the name prop is to define the name of the field for the FormData . I think the Ant docs have this incorrect as it states that it is for the name of the file being uploaded. This name value should match the field value set in the Multer configuration.

Test it out

Deploy the dev server and give it a try. Files will now upload into the designated folder in the Multer configuration!

Resources

https://ant.design/components/upload/

https://www.npmjs.com/package/multer