Axios File Upload example

In this tutorial, I will show you an Axios File Upload example (with/without progress) using multipart/form-data.

Related Posts:
Axios Tutorial: Get/Post/Put/Delete request example
Axios Interceptors tutorial with example
React File Upload with Axios and Progress Bar
Vue File Upload example with Axios and Progress Bar


Axios Features

Axios can run in the Node.js and Browser with the same codebase.
– On the server-side it uses the native Node.js http module
– On the client-side (browser) it uses XMLHttpRequests

Additionally, there are important features that you should know:

  • Supports the Promise API
  • Intercept request and response (Axios Interceptors tutorial)
  • Transform request and response data
  • Cancel requests
  • Automatic transforms for JSON data
  • Client side support for protecting against XSRF

(from https://github.com/axios/axios#features)

How to install Axios

We can add Axios to our project/code with one of following simple ways:

– npm:

npm install axios

– bower:

bower install axios

– yarn:

yarn add axios

– CDN:

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

Or:

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

Axios Response Object schema

The response for a Axios request contains:

  • data: parsed response body provided by the server
  • status: HTTP status code
  • statusText: HTTP status message
  • headers: HTTP headers (lower case)
  • config: the request config that was provided to axios
  • request: the last client request instance that generated this response

For example:

{
  "data": {
    "message": "Uploaded the file successfully: bezkoder.sql"
  },
  "status": 200,
  "statusText": "OK",
  "headers": {
    "content-length": "58",
    "content-type": "application/json; charset=utf-8"
  },
  "config": {
    "transitional": {
      "silentJSONParsing": true,
      "forcedJSONParsing": true,
      "clarifyTimeoutError": false
    },
    "transformRequest": [
      null
    ],
    "transformResponse": [
      null
    ],
    "timeout": 0,
    "xsrfCookieName": "XSRF-TOKEN",
    "xsrfHeaderName": "X-XSRF-TOKEN",
    "maxContentLength": -1,
    "maxBodyLength": -1,
    "headers": {
      "Accept": "application/json, text/plain, */*"
    },
    "baseURL": "http://localhost:8080",
    "method": "post",
    "url": "/upload"
  }
}

Axios File Upload with multipart/form-data

We will use FormData object for constructing a set of key/value pairs: form fields and their values, this object is easily sent using the axios.post() method.
Remember to set the encoding type to "multipart/form-data".

let formData = new FormData();
formData.append("file", selectedFile);

axios.post('/bezkoder.com/upload', formData, {
    headers: {
      "Content-Type": "multipart/form-data",
    }
  });

Axios File Upload Response Body

Axios Response Object has data field that contains the parsed response body.
We can use then or await to receive the response body as follows:

axios.post('/bezkoder.com/upload', formData, {
    headers: {
      "Content-Type": "multipart/form-data",
    }
  })
  .then(function (response) {
    console.log(response.data);
  });

const { data } = await axios.post(url);

Axios File Upload Error handling

We use catch() for handling errors.

axios.post('/bezkoder.com/upload', formData, {
    headers: {
      "Content-Type": "multipart/form-data",
    }
  })
  .then(...)
  .catch(function (error) {
    if (error.response) { // get response with a status code not in range 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) { // no response
      console.log(error.request);
      // instance of XMLHttpRequest in the browser
      // instance ofhttp.ClientRequest in node.js
    } else { // Something wrong in setting up the request
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

Axios File Upload Error handling with async-await

If you want to use async-await, just wrap the axios call with try/catch block.

async function uploadFile() {
  try {
    const response = await axios.post('/bezkoder.com/upload', formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      }
    });
    console.log(response);
  } catch (error) {
    if (error.response) { // get response with a status code not in range 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) { // no response
      console.log(error.request);
    } else { // Something wrong in setting up the request
      console.log('Error', error.message);
    }
    console.log(error.config);
  }
}

Axios File Upload Progress

We pass onUploadProgress to exposes progress events. This progress event are expensive (change detection for each event), so you should only use when you want to monitor it.

The progress will be calculated basing on event.loaded and event.total.

async function uploadFile() {
  const onUploadProgress = (event) => {
    const percentage = Math.round((100 * event.loaded) / event.total);
    console.log(percentage);
  };

  try {
    const response = await axios.post('/bezkoder.com/upload', formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      }
      onUploadProgress,
    });

    console.log(response);
  } catch (error) {
    ...
  }
}

You can use Bootstrap Progress Bar for displaying the percentage:

  • .progress as a wrapper
  • inner .progress-bar to indicate the progress
  • .progress-bar requires style to set the width by percentage
  • .progress-bar also requires role and some aria attributes to make it accessible
  • label of the progress bar is the text within it (innerHTML)
  • aria-valuenow attribute for percentage (0-100)
<div id="progress" class="progress">
  <div
    id="progress-bar"
    class="progress-bar progress-bar-info"
    role="progressbar"
    aria-valuemin="0"
    aria-valuemax="100"
  ></div>
</div>
let progressBarElement = document.getElementById("progress-bar");
progressBarElement.innerHTML = "0%";
progressBarElement.setAttribute("aria-valuenow", 0);
progressBarElement.style.width = "0%";

const onUploadProgress = (event) => {
  const percentage = Math.round((100 * event.loaded) / event.total);
  progressBarElement.innerHTML = percentage + "%";
  progressBarElement.setAttribute("aria-valuenow", percentage);
  progressBarElement.style.width = percentage + "%";
};

Get all uploaded files

We use Axios to send HTTP GET request to get the files’ information and assign the result to fileInfos array, which is an array of {name, url} objects.

To display List of uploaded files, we iterate over fileInfos array using map() function. On each file item, we use file.url as href attribute and file.name for showing text.

function getHTMLFiles(fileInfos) {
  if (fileInfos && fileInfos.length) {
    const files = fileInfos.map(
      (file, index) =>
        `<li key='` + index + `'>\
          <a href='` + file.url + `'>` + file.name + `</a>\
        </li>`
    );

    return (
      `<div>List of Files</div>\
        <ul>` +
      files.join("") +
      `</ul>`
    );
  }

  return `No file was found!`;
}

async function getFiles() {
  try {
    const res = await axios.get("/bezkoder.com/files");

    filesElement.innerHTML = getHTMLFiles(res.data);
  } catch (err) {
    ...
  }
}

Rest API for File Upload

Here is the API that our Axios Client will work with:

Methods Urls Actions
POST /upload upload a File
GET /files get List of Files (name & url)
GET /files/[filename] download a File

You can find how to implement the Rest API Server at one of following posts:
Node.js Express File Upload Rest API example
Node.js Express File Upload to MongoDB example
Node.js Express File Upload to Google Cloud Storage example
Spring Boot Multipart File upload (to static folder) example

Or: Spring Boot Multipart File upload (to database) example

Note: You need to configure CORS with origin: "*" for working well with the example in this tutorial.

Axios File Upload example

We’re gonna create a Axios File Upload example in that user can:

  • see the upload process (percentage) with progress bar
  • view all uploaded files
  • download the file by clicking on the file name

axios-file-upload-progress

Click on Get List of Files button:

axios-upload-file-multipartform-data

– First we import Axios and Bootstrap, then we write some HTML code for the UI.

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Axios File upload</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    />
  </head>
  <body>
    <div class="container" style="max-width: 600px">
      <h3 class="mb-3">Axios File Upload</h3>

      <div class="input-group">
        <div class="custom-file">
          <input id="input-file" type="file" class="custom-file-input" />
          <label id="input-file-label" class="custom-file-label" for="input-file">Choose file</label>
        </div>
        <div class="input-group-append">
          <button
            class="btn btn-outline-success"
            type="button"
            onClick="uploadFile()"
          >
            Upload
          </button>
        </div>
      </div>

      <div id="progress" class="progress my-3" style="display: none">
        <div
          id="progress-bar"
          class="progress-bar progress-bar-info"
          role="progressbar"
          aria-valuemin="0"
          aria-valuemax="100"
        ></div>
      </div>

      <div id="message" class="alert-light" role="alert"></div>

      <button class="btn btn-info btn-sm my-3" onClick="getFiles()">
        Get List of Files
      </button>

      <div id="list-files" class="card" style="display: none"></div>

      <p class="mt-3">
        ©
        <a href="https://www.bezkoder.com" target="_blank">bezkoder.com</a>
      </p>
    </div>

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

    <script src="main.js"></script>
  </body>
</html>

This is the user interface:

axios-file-upload-demo

For 2 onClick events, there are 2 functions that use Axios for working with Rest API Server:

  • uploadFile(): POST form data with a callback for tracking upload progress
  • getFiles(): GET list of Files’ information

main.js

const instance = axios.create({
  baseURL: "http://localhost:8080"
});

document.getElementById("input-file").addEventListener("change", (e) => {
  if (e.target.files.length) {
    document.getElementById("input-file-label").innerHTML = e.target.files[0].name;
  }
});

async function uploadFile() {
  let messageElement = document.getElementById("message");
  messageElement.innerHTML = "";

  const selectedFile = document.getElementById("input-file").files[0];
  let formData = new FormData();

  formData.append("file", selectedFile);

  document.getElementById("progress").style.display = "flex";
  let progressBarElement = document.getElementById("progress-bar");
  progressBarElement.innerHTML = "0%";
  progressBarElement.setAttribute("aria-valuenow", 0);
  progressBarElement.style.width = "0%";

  const onUploadProgress = (event) => {
    const percentage = Math.round((100 * event.loaded) / event.total);
    progressBarElement.innerHTML = percentage + "%";
    progressBarElement.setAttribute("aria-valuenow", percentage);
    progressBarElement.style.width = percentage + "%";
  };

  try {
    const res = await instance.post("/upload", formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
      onUploadProgress,
    });

    const result = {
      status: res.status + "-" + res.statusText,
      headers: res.headers,
      data: res.data
    };

    messageElement.innerHTML = htmlizeResponse(result);
  } catch (err) {
    messageElement.innerHTML = htmlizeResponse(err);
  }
}

async function getFiles() {
  let messageElement = document.getElementById("message");
  messageElement.innerHTML = "";

  let filesElement = document.getElementById("list-files");
  filesElement.innerHTML = "";

  try {
    const res = await instance.get("/files");

    const result = {
      status: res.status + "-" + res.statusText,
      headers: res.headers,
    };

    messageElement.innerHTML = htmlizeResponse(result);
    filesElement.innerHTML = getHTMLFiles(res.data);
    document.getElementById("list-files").style.display = "block";
  } catch (err) {
    messageElement.innerHTML = htmlizeResponse(err);
  }
}

function htmlizeResponse(res) {
  return (
    `<div class="alert alert-secondary mt-2" role="alert"><pre>` +
    JSON.stringify(res, null, 2) +
    "</pre></div>"
  );
}

function getHTMLFiles(fileInfos) {
  if (fileInfos && fileInfos.length) {
    const files = fileInfos.map(
      (file, index) =>
        `<li class="list-group-item" key='` + index + `'>\
          <a href='` + file.url + `'>` + file.name + `</a>\
        </li>`
    );

    return (
      `<div class="card-header">List of Files</div>\
        <ul class="list-group list-group-flush">` +
      files.join("") +
      `</ul>`
    );
  }

  return `No file was found!`;
}

Conclusion

With this Axios tutorial, you’ve known many ways to upload file using Axios (with multipart/form-data). You can also use it in:

– React App: React File Upload with Axios
– Vue App: Vue File Upload example with Axios

Happy Learning! See you again.

Further Reading