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
viareq.body.username
, and the uploaded file viareq.files.userPicture
!
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.