File Uploads using Fetch API and VueJS

Part 3 of 4 in Using Fetch API with VueJS
Dan Pastori avatar
Dan Pastori November 22nd, 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:

<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:

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

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

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.

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!

Keep Reading
View the course View the Course Using Fetch API with VueJS
Up Next → Fetch API Components with Vue 3 Composition API

Support future content

The Ultimate Guide to Building APIs and Single-Page Applications with Laravel + VueJS + Capacitor book cover.

Psst... any earnings that we make off of our book is being reinvested to bringing you more content. If you like what you read, consider getting our book or get sweet perks by becoming a sponsor.

Written By Dan

Dan Pastori avatar Dan Pastori

Builder, creator, and maker. Dan Pastori is a Laravel certified developer with over 10 years experience in full stack development. When you aren't finding Dan exploring new techniques in programming, catch him at the beach or hiking in the National Parks.