Uploading files and processing them in the backend is a common functionality in web applications, such as uploading avatars or attachments. In this article, we will learn how to upload files to the server using JavaScript.

Uploading Files Client-Side

To enable file upload functionality in our web app, we start by adding an HTML file input element:

<input type="file" id="fileUpload" />

Next, we register a change handler on the #fileUpload DOM element. When the user selects a file, we trigger the handleImageUpload() function and pass in the selected file.

const handleImageUpload = event => {
  const files = event.target.files;
  const formData = new FormData();
  formData.append('myFile', files[0]);

  fetch('/saveImage', {
    method: 'POST',
    body: formData
  })
    .then(response => response.json())
    .then(data => {
      console.log(data.path);
    })
    .catch(error => {
      console.error(error);
    });
};

document.querySelector('#fileUpload').addEventListener('change', event => {
  handleImageUpload(event);
});

We use the Fetch API to send the file to the server. Once the server successfully processes the file, it will return the image path in the path property of the response. This allows us to update the interface as needed.

Handling File Upload Server-Side with Node.js

Now let’s look at the server-side implementation using Node.js with the Express framework.

First, install the express-fileupload npm module:

npm install express-fileupload

Then, add it to your middleware:

const fileupload = require('express-fileupload');

// use it as middleware
app.use(fileupload());

Adding this middleware allows the server to parse file uploads properly. Otherwise, the req.files object will be undefined.

To handle file uploads, define a route for handling the /saveImage endpoint:

app.post('/saveImage', (req, res) => {
  const fileName = req.files.myFile.name;
  const path = __dirname + '/images/' + fileName;

  req.files.myFile.mv(path, (error) => {
    if (error) {
      console.error(error);
      res.writeHead(500, {
        'Content-Type': 'application/json'
      });
      res.end(JSON.stringify({ status: 'error', message: error }));
      return;
    }

    res.writeHead(200, {
      'Content-Type': 'application/json'
    });
    res.end(JSON.stringify({ status: 'success', path: '/img/houses/' + fileName }));
  });
});

In this example, we use the mv property of the uploaded file, which is provided by the express-fileupload module, to move the file to the desired path. Then, we communicate either the success or an error back to the client.

Checking File Properties Client-Side

If you need to check the file type or size before uploading it, you can preprocess them in the handleImageUpload function. Here’s an example that checks if the file is an image and its size is within the allowed limit:

const handleImageUpload = event => {
  const files = event.target.files;
  const myImage = files[0];
  const imageType = /image.*/;

  if (!myImage.type.match(imageType)) {
    alert('Sorry, only images are allowed');
    return;
  }

  if (myImage.size > (100 * 1024)) {
    alert('Sorry, the max allowed size for images is 100KB');
    return;
  }

  // ...
};

By using these techniques, you can implement file upload functionality in your web app and handle the files both on the client and server side with ease.