Using Fetch API with Vue.js (Part 3 of 4)

File Uploads using Fetch API and VueJS

Dan Pastori

November 23rd, 2021

We've talked about file uploads with Axios a ton of different ways. Since we are just comparing the Fetch API with Axios, I won't do as many examples. However, we will touch on the differences between the Fetch API and Axios when uploading files. Once again, if you want to see exactly how this component works, check out our GitHub repo.

Step 1: Preparing Your File Upload with Fetch API

For this request, we will be using a POST request. However, you can use any proper HTTP Verb such as POST, PUT, or PATCH. The two main differences between this type of request that includes a file and one that doesn't is the Content-Type is not JSON and the body is Form Data. This is exactly the same as Axios. Let's dive into that.

Step 2: Uploading a File with Fetch API and VueJS

The first thing we need to do is create our file input in our VueJS template. It should look like this:

File input template

<input type="file" @change="handleFileUpload( $event )"/>

This will be the same whether you are using Axios or the Fetch API. The big thing to note is we apply a change listener through @change and pass the $event to the listener. Let's add that method to our component:

File upload handler method

handleFileUpload( e ){
    this.form.icon = e.target.files[0];
}

What this does, is once a user selects a file, we grab the file from the event and store it locally. We store it to our form.icon reference so we can use it later on. What's stored is a representation of the File object {LINK_TO MDN}. We can use this to send the file through the Fetch API or Axios.

Now it's time to implement both of our requests:

Fetch API File Upload

Fetch API file upload implementation

let formData = new FormData();

formData.append( 'method', this.form.method );
formData.append( 'icon', this.form.icon );

fetch( '<https://api.roastandbrew.coffee/api/v1/brew-methods>', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer '+this.token,
        'Accept': 'application/json',
        'Content-Type': 'multipart/form-data'
    },
    body: formData
} )
.then( function( response ){
    if( response.status != 201 ){
        this.fetchError = response.status;
    }else{
        response.json().then( function( data ){
            this.fetchResponse = data;
        }.bind(this));
    }
}.bind(this));

Axios File Upload

Axios file upload implementation

let formData = new FormData();

formData.append( 'method', this.form.method );
formData.append( 'icon', this.form.icon );

axios.post(' <https://api.roastandbrew.coffee/api/v1/brew-methods>', 
    formData, {
    headers: {
        'Authorization': 'Bearer '+this.token,
        'Content-Type': 'multipart/form-data'
    }
} )
.then( function( response ){
    this.axiosResponse = response.data;
}.bind(this))
.catch( function( error ){
    this.axiosError = error;
}.bind(this));

Both of these request should look very similar to sending a standard POST request. However, there are a few key differences.

Let's look at the differences between Fetch API request and the Axios. The first thing we do is implement a FormData() object.. This allows us to handle and send files. We need this request to be a FormData object so we can send files to the server.

FormData initialization

let formData = new FormData();

formData.append( 'method', this.form.method );
formData.append( 'icon', this.form.icon );

The next difference is we need to change the Content-Type to 'Content-Type': 'multipart/form-data'. This alerts the endpoint we are using a multipart/form-data request and the server should look for attached files. We have to add this header to Axios as well.

The final difference is in the body setting. Instead of JSON.stringify() we pass the FormData() object we created (formData) as the setting for body. This is very similar to the Axios request where we pass formData as the second parameter to the axios.post() method.

Gotchas

There are a few gotchas with doing file uploads. First, as I mentioned in the intro, you can use PUT to send files to the server as well. However, if you are using a Laravel backend, you have to send this as a POST request and append _method=PUT to the body (formData.append('_method', 'PUT')). Laravel will not pick up a multipart/form-encoded request through PUT.

Next, if you've checked out the Uploading Files with VueJS and Axios Course, you'd notice a progress indicator. With Axios, you can easily build in a progress indicator to show progress on uploading large files. As of this writing, you can not do this with the Fetch API. I really hope they fix this soon since it's huge for UX. If I run across a fix, I'll update this article.

Conclusion

Uploading a file with the Fetch API and VueJS should look very similar to sending a POST, PUT, or PATCH request with only a few changes. Next up, we will try to abstract some of the settings to a standard location to clean up the Fetch API requests and make them easier to use. If you have any questions, be sure to reach out on Twitter (@danpastori) or on the community!

Want to work together?

Professional developers choose Server Side Up to ship quality applications without surrendering control. Explore our tools and resources or work directly with us.

Join our community

We're a community of 3,000+ members help each other level up our development skills.

Platinum Sponsors

Active Discord Members

We help each other through the challenges and share our knowledge when we learn something cool.

Stars on GitHub

Our community is active and growing.

Newsletter Subscribers

We send periodic updates what we're learning and what new tools are available. No spam. No BS.

Sign up for our newsletter

Be the first to know about our latest releases and product updates.

    Privacy first. No spam. No sharing. Just updates.