How to upload files on the server using Fetch API

Uploading files is one of the most common features in a web application nowadays. There are many JavaScript libraries available that handle file uploads like a breeze.

But let's not load a whole library just for this single feature that can be easily handled in native JavaScript using Fetch API. Fetch is a promise-based modern replacement of XHR for making HTTP requests in the browser.

Fetch API file upload

Let's add the following HTML input element to your website:

<input type="file" id="avatar">

Now add an event listener on the input that will be triggered when the user chooses a file:

// select file input
const input = document.getElementById('avatar')

// add event listener
input.addEventListener('change', () => {
  uploadFile(input.files[0])
})

Next, add uploadFile() method that receives a File object as input and uploads it on the server with fetch() using the FormData interface:

const uploadFile = file => {
  // add the file to the FormData object
  const fd = new FormData()
  fd.append('avatar', file)

  // send `POST` request
  fetch('/upload-avatar', {
    method: 'POST',
    body: fd
  })
    .then(res => res.json())
    .then(json => console.log(json))
    .catch(err => console.error(err))
}

Do not set the Content-Type header for multi-part request with fetch(). The browser will automatically add the content type header, including the form boundary.

Validate file type & size

You can also validate the properties (like file type and file size) of the file before starting uploading on the server:

const uploadFile = file => {
  // check file type
  if (!['image/jpeg', 'image/gif', 'image/png', 'image/svg+xml'].includes(file.type)) {
    console.log('Only images are allowed.')
    return
  }

  // check file size (< 2MB)
  if (file.size > 2 * 1024 * 1024) {
    console.log('File must be less than 2MB.')
    return
  }

  // ...
}

Uploading file on the server using Node.js

Here is an example that handles the above file upload request in Node.js. I am using the express-fileupload library, a simple Express middleware for uploading files. It parses multipart/form-data requests, extracts the files if available, and makes them available under the req.files property:

app.post('/upload-avatar', async (req, res) => {
  try {
    if (!req.files) {
      res.send({
        status: false,
        message: 'No file uploaded'
      })
    } else {
      // Use the name of the input field (i.e. "avatar") to retrieve the uploaded file
      let avatar = req.files.avatar

      // Use the mv() method to place the file in the upload directory (i.e. "uploads")
      avatar.mv('./uploads/' + avatar.name)

      //send response
      res.send({
        status: true,
        message: 'File is uploaded',
        data: {
          name: avatar.name,
          mimetype: avatar.mimetype,
          size: avatar.size
        }
      })
    }
  } catch (err) {
    res.status(500).send(err)
  }
})

Read the Uploading Files in Node.js and Express guide to learn how to handle file uploads in Node.js.

Uploading file on the server using Spring Boot

If you are planning to use Spring Boot for the back end, here is an example code snippet that processes the above file upload request in Spring Boot:

@PostMapping("/upload-avatar")
@ResponseBody
public ResponseEntity<String> fileUpload(MultipartFile avatar) {
    try {

        // upload directory - change it to your own
        String UPLOAD_DIR = "/opt/uploads";

        // create a path from the file name
        Path path = Paths.get(UPLOAD_DIR, avatar.getOriginalFilename());

        // save the file to `UPLOAD_DIR`
        // make sure you have permission to write
        Files.write(path, avatar.getBytes());
    }
    catch (Exception ex) {
        ex.printStackTrace();
        return new ResponseEntity<>("Invalid file format!!", HttpStatus.BAD_REQUEST);
    }

    return new ResponseEntity<>("File uploaded!!", HttpStatus.OK);
}

Read the Uploading Files in Spring Boot guide for handling single and multiple file uploads in a Spring Boot application.

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.

You might also like...

Digital Ocean

The simplest cloud platform for developers & teams. Start with a $200 free credit.

Buy me a coffee ☕

If you enjoy reading my articles and want to help me out paying bills, please consider buying me a coffee ($5) or two ($10). I will be highly grateful to you ✌️

Enter the number of coffees below:

✨ Learn to build modern web applications using JavaScript and Spring Boot

I started this blog as a place to share everything I have learned in the last decade. I write about modern JavaScript, Node.js, Spring Boot, core Java, RESTful APIs, and all things web development.

The newsletter is sent every week and includes early access to clear, concise, and easy-to-follow tutorials, and other stuff I think you'd enjoy! No spam ever, unsubscribe at any time.