Axios Multipart Form Data - Sending File Through a Form with JavaScript

Introduction

Multipart/Form-Data is one of the encoding types that allows files to be included in your form data before it's transferred to the server for processing. Other encoding types can be used to achieve non-file transfers:

  • application/x-www-form-urlencoded - Encodes data as a query string - separating key-value pairs (assigned with =), with symbols such as &.
  • multipart/form-data - Allow files to be included in as form data.
  • text/plain - It sends data as plain text (without encoding) and is mostly used for debugging, not production.

And any of this can be added to an HTML form tag via the (optional) enctype attribute:

<form action="/path/to/api" method="POST" encytpe="ENCTYPE_HERE">
</form>

They operate in a fairly straightforward manner, and you're likely to have seen them employed with an HTML <form> tag before, though, the default works well for most cases so the attribute is commonly omitted.

In this guide, we'll take a look at how to asynchronously send files and other form data with Axios to a Node.js (Express) server, as well as how to receive this data in the backend for processing.

Installing Axios

Axios is a Promise-based (asynchronous) HTTP client, present and used in many Node.js projects! It's quite common to use Axios to send HTTP requests, rather than fetch().

If you'd like to read more about sending HTTP requests with fetch() - read our Using fetch to Send HTTP Requests in JavaScript or Making HTTP Requests in Node.js with node-fetch!

To use Axios in your Node projects - you can easily install it via npm:

$ npm install axios
# OR
$ yarn add axios

Alternatively, you can include its CDN directly (or download its files to your local machine) and include the library in your markup as follows:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Setting the enctype with Axios and HTML

To send multipart data (files) through form data - you'll have to set the encoding type. There are a couple of ways you can do this, with no clear or distinct "winner" - they're functionally equivalent per request in the end. With Axios - you can set the default global encoding type:

axios.defaults.headers.post['Content-Type'] = 'multipart/form-data';

This enforces all Axios requests to be of multipart/form-data encoding type. Alternatively, you can define the type for each individual request, by altering the headers:

axios.post("/path/to/api", data, {
  headers: {
    "Content-Type": "multipart/form-data",
  },
});

Or you can just set the enctype attribute in the <form> tag of a specific form, and Axios will simply adopt that form's encoding type:

<form action="/some-endpoint" method="HTTP_METHOD" enctype="multipart/form-data">
</form>

Axios + Express

For our example, we will create a simple form with two inputs, one for the user to submit their name and the other for them to select a profile image:

<form action="/update-profile" method="post">
    <input type="text" name="username" placeholder="Enter name" />
    <input type="file" name="userPicture" />
    <button type="submit">Submit</button>
</form>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Without using Axios - this would let the default set of events unfold. Clicking the "Submit" button would send a POST request to the /update-profile endpoint of our server. However - we can override this default behavior by attaching an event listener to the button, and preventing the default events!

Again, sending Axios requests entails asynchronicity - and we can alter our headers and otherwise customize the request before sending it out. Let's attach an event listener, prevent the default behavior and send our form data via Axios instead:

<script>

  const form = document.querySelector("form");
  form.addEventListener("submit", (e) => {
    e.preventDefault();
    const formData = new FormData(form);
    axios
      .post("http://localhost:5000/update-profile", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      })
      .then((res) => {
        console.log(res);
      })
      .catch((err) => {
        console.log(err);
      });
  });
</script>

Note: Again, you could've set the enctype of the form, or altered the headers with Axios. The choice is fully on you.

Awesome! When the form is filled, and the "Submit" button is clicked - the request is forwarded to the http://localhost:5000/update-profile endpoint, with support for uploading files. Now - let's define the endpoint that receives this request and processes it.

Express Backend

For our backend - the simplest and cleanest way to spin up a REST API is via Express.js, which deals with the boilerplate of setting up a server and handling requests - allowing you to focus on development instead of setup.

If you'd like to read more about creating REST APIs with Node and Express, read our Guide to Building a REST API with Node and Express!

Express works great by itself - but it's meant to be minimal out of the box, and expandable with middleware. Various simple (or complex) middleware can be installed on top of it to expand the core functionality, when required.

To use Express - we'll want to install it via npm. For simple file upload handling with Express, we can utilize the express-fileupload middleware, which is also easily installed via npm:

$ npm install express express-fileupload 

Now, let's start up a server and define an endpoint that accepts our POST request to /update-profile:

// Import the library
const express = require("express");
var fileupload = require("express-fileupload");

// Create app instance
const app = express();

// Register and set up the middleware
app.use(fileupload());
app.use(express.urlencoded({ extended: true }));

// Request handler/endpoint
app.post("/update-profile", (req, res) => {
    let username = req.body.username;
    let userPicture = req.files.userPicture;
    res.send(`
      Your username is: ${username}
      Uploaded image name is: ${userPicture.name}
    `);
});

// Start up the server
app.listen(5000, () => {
    console.log("Server started on port 5000");
});

The request (req) passed to the request handler contains the data sent by our form. Its body contains all of the data from the fields we've set up, such as the username. Any and all files will be located under the files field of the req object!

We can thus access the input username via req.body.username, and the uploaded file via req.files.userPicture!

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

When we submit the form via our HTML page, a request is sent to this API, and we receive the following response in our browser console:

Your username is: NAME_YOU_ENTERRED
Uploaded image name is: UPLOADED_FILE_NAME

Additionally, if we log the req.files.userPicture itself to the console, it returns all of the information about our file, such as the file name, encoding type, and other information related to the file.

Conclusion

In this guide, we've taken a look at the enctype attribute and covered how it works. We've then explored how to set the enctype with Axios - a popular asynchronous HTTP library, and send POST requests containing multipart/file data.

Finally, we've spun up a REST API to handle the request and accept the incoming file and other form data.

The source code is available on GitHub.

Last Updated: May 23rd, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms