Vue Axios Upload Image with Multipart Form Data Tutorial

Vue multipart form data file upload tutorial; In this guide, you will learn how to create a vue image file upload feature, upload image to server using multipart/form-data. Also, understand how to create file uploading API using multer, node and express js.

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to “multipart/form-data”.

If you want to upload a file in vue, Axios is the tool we are using to make an HTTP post request to post multipart form data. Furthermore, we teach you how to store the image file in the MongoDB database using the node and express REST API.

Suppose you love the vue framework but don’t know much about it. In that case, this tutorial gives you the vindication of creating an essential feature that might be imperative in your development span.

Here are the topics that we are eloquently addressing in this tutorial using a pragmatic approach.

  • How to upload image files in Vue js
  • How to use Axios HTTP client to post multipart form data
  • How to create node backend
  • How to develop express js file upload REST API
  • How to post form data and store it in MongoDB
  • How to use multer to upload files in node js application

How to Use Axios to Post Multipart Form Data in Vue

  • Step 1: Create Vue Project
  • Step 2: Add Axios Http Client
  • Step 3: Create File Upload Component
  • Step 4: Create Node, Express File Upload API
  • Step 5: Upload Image using Multipart Form Data
  • Step 6: Start Vue Application

Create Vue Project

In the first, step head over to the terminal, use the following command to manifest a new vue project.

vue create vue-social

Add Axios Http Client in Vue

Thereafter, take a step inside the vue app and then install the important Axios package using the given command.

npm install axios

Create File Upload Component

In the next step you require to create a new ImageUpload.vue file inside the components folder and make sure to add the component in the src/App.vue file.

<template>
  <div class="container mt-5 text-center">
    <ImageUpload />
  </div>
</template>

<script>
    import ImageUpload from './components/ImageUpload.vue'

    export default {
      name: 'App',
      components: {
        ImageUpload
      } 
    }
</script>

Create Node, Express File Upload API

Create the backend folder at the root of the vue app, and this will be the place for keeping the REST API code.

mkdir backend && cd backend

Plus, execute command to create separate package.json file with the help of npm initializer.

npm init

Further, run command to install third-party packages.

npm install multer express mongoose cors body-parser uuid

After that, install the nodemon library.

npm install nodemon --save-dev

To set up a mongo database, create the following folder and file in the backend directory.

mkdir db && cd db && touch database.js

Update backend/db/database.js file.

module.exports = {
    db: 'mongodb://localhost:27017/vuedb'
}

Now, create run command to create following directory and the file.

mkdir models && cd models && touch File.js

In this file, define the file schema for the uploading file in the database, so update backend/models/File.js file.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const fileSchema = new Schema({
    _id: mongoose.Schema.Types.ObjectId,
    imagesArray: {
        type: Array
    }
}, {
    collection: 'files'
})

module.exports = mongoose.model('File', fileSchema)

Further, run command to generate provided folder and file name.

mkdir routes && cd routes && touch file.route.js

Routes are the path name of the endpoint, which is responsible for processing the request on api call, therefore update backend/routes/file.route.js file.

let express = require('express');
let mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid');
let multer = require('multer');
let router = express.Router();

const DIR = './public/';
let File = require('../models/File');


const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, DIR);
    },
    filename: (req, file, cb) => {
        const fileName = file.originalname.toLowerCase().split(' ').join('-');
        cb(null, uuidv4() + '-' + fileName)
    }
});


var upload = multer({
    storage: storage,
    fileFilter: (req, file, cb) => {
        if (file.mimetype == "image/png" || file.mimetype == "image/jpg" || file.mimetype == "image/jpeg") {
            cb(null, true);
        } else {
            cb(null, false);
            return cb(new Error('File type not accepted (.png, .jpg, .jpeg)'));
        }
    }
});

router.post('/multi-images-upload', upload.array('imagesArray', 8), (req, res, next) => {
    const reqFiles = [];

    const url = req.protocol + '://' + req.get('host')

    for (var i = 0; i < req.files.length; i++) {
        reqFiles.push(url + '/public/' + req.files[i].filename)
    }

    const user = new File({
        _id: new mongoose.Types.ObjectId(),
        imagesArray: reqFiles
    });

    user.save().then(result => {
        res.status(201).json({
            message: "Uploaded!",
            userCreated: {
                _id: result._id,
                imagesArray: result.imagesArray
            }
        })
    }).catch(err => {
        console.log(err),
            res.status(500).json({
                error: err
            });
    })
})

router.get("/", (req, res, next) => {
    File.find().then(response => {
        res.status(200).json({
            message: "Images fetched!",
            posts: response
        });
    });
});

module.exports = router;

Create a `public` folder to keep the uploaded images.

mkdir public

Lastly, create backend/index.js file, accumulate all the code which will invoke the node and express server.

let express = require('express');
let mongoose = require('mongoose');
let bodyParser = require('body-parser');
let mongo = require('./db/database');
let cors = require('cors');

const REST_API = require('../backend/routes/file.route')

mongoose.Promise = global.Promise;
    mongoose.connect(mongo.db, {
        useUnifiedTopology: true,
        useNewUrlParser: true
    }).then(() => {
        console.log('Database connected')
    },
    err => {
        console.log(err)
    }
)

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(cors());

app.use('/public', express.static('public'));
app.use('/api', REST_API)

const port = process.env.PORT || 8888;

app.listen(port, () => {
    console.log('Connected : ' + port)
})

app.use((req, res, next) => {
    setImmediate(() => {
        next(new Error('Error occured'));
    });
});

Now, execute both the commands on two separate consoles to run the node backend.

nodemon
mongo

Congratulations, you have created the following APIs to view the data of the file and to make the HTTP post request.

http://localhost:8888/api

http://localhost:8888/api/multi-images-upload

Upload Image using Multipart Form Data

Create a simple form with a file input field, add a change event handler and tie the onChange() method to it.

Import Axios library, make the HTTP request to post the form data and store the file to the public folder and file path in the mongo database.

Update components/ImageUpload.vue file.

<template>
  <div>
      <form @submit.prevent="onUpload">
          <div class="form-group">
              <input type="file" name="imagesArray" @change="onChange">
          </div>
          <div class="form-group">
              <button class="btn btn-success">Submit</button>
          </div>
      </form>
  </div>
</template>

<script>
import axios from "axios";

export default {
  data() {
      return {
         imagesArray: null
      };
    },
    methods: {
        onChange (event) {
          this.imagesArray = event.target.files[0]
        },
        onUpload() {
          const formData = new FormData()
          formData.append('imagesArray', this.imagesArray, this.imagesArray.name)
          axios.post('http://localhost:8888/api/multi-images-upload', formData, {
          }).then((response) => {
            console.log(response)
          })
        }  
    }

}
</script>

<style scoped lang="css">
.container {
  max-width: 500px;
}
</style>

Start Application

In the final section of this tutorial, we start the vue app. Thus, run the development server by executing the following command.

npm run serve

Vue multipart/form-data example

Conclusion

In this detailed guide, we discussed some significant instructions to post multipart/form-data in the vue js app to upload images to the MongoDB database with the help of Node, Express and Multer middleware. The confluence of all these services and middleware will get you acquainted with some server-side and client-side technologies.

Though this guide is for beginners, you can add more features in vue image upload functionally with your enhanced discretion. We believe we haven’t fallen into the trap of procrastination and gave you the sense of gratification in a calm and composed manner. We hope you liked our fidelity and truly understood how to post multipart form data in vue js to upload the image files to the mongo database.