Dan Pastori
November 16th, 2020
Creating an API wrapper using VueJS & Axios makes your API interfacing code extremely fluid, modular, and maintainable. Before we get started, those using NuxtJS should skip to the next tutorial. This will tutorial will ONLY work with VueJS and not within NuxtJS.
With that being said, so far we've installed Axios and got it to work with VueJS and configured Axios to work globally. We've also went through a few more complex requests like POST, PUT, & PATCH. In this tutorial we will abstract all of our API requests into wrapper modules. Before we get started, let's begin with why.
Simply put, for code maintainability and re-usability. What we will be doing is taking all of our API requests for a specific resource and wrapping them in a module. If you need to make a request to an API endpoint using this module with a Vuex action, you can. If you need to make an API request in a component, you can do that as well. This process will work with your own API or a 3rd Party API.
However, the best part is, if you need to change a request in any way (like adding a header, upgrading API versions, etc), you update it once. This will update the request through your entire app! It's really convenient and easy to use. In the next tutorial I'll show you how to do this with NuxtJS if that's what you are using. Let's get started!
The way I approach development is to set up "buckets" (which are just folders) to house code and pseudo-structure before I start developing. Before I add any API wrapping modules, I always create an /api
directory at the root of my app. In this directory I will place all of my modules.
If you have a very complex API, feel free to add sub-directories to this as well. The more code organization, the better! Let's add our first module.
Let's say we have an API focused around music. This API has endpoints that allow us to manage the songs resource. We can view all songs (GET
), create a song (POST
), update a song (PUT
), view a song (GET
) and delete a song (DELETE
). There are a variety of places in our application where we interact with this resource, so we want to build a module.
The first step is to add the file: /api/songs.js
. In this file, add the following code:
export default {
index( params ){
},
show( id ){
},
update( id, data ){
},
create( data ){
},
delete( id ){
}
}
If you've worked with Laravel in the past, this naming convention may look familiar. If you haven't, you might be wondering what's up with the names of these methods. Laravel uses a naming scheme for resource endpoints that I really enjoy implementing on both back and front end. If you want to read about it, check out their documentation on Resource Controllers.
You don't have to use Laravel as your backend and you really don't even have to use this naming format. These are just the methods that we will be implementing for each resource regardless of first party or third party. Each method will return an Axios request which is a promise. This way we can efficiently handle the request in context.
index
EndpointWhen following a resource naming scheme, the index
endpoint will load all of a specific resource. It's a GET
request that usually accepts parameters so you can filter/order your response. You don't really want to load all of the resource when you call this route. Especially in larger systems where this could literally be over a million items, so these filters usually come in handy or maybe even be required.
Let's take a look at our music app example. Say we want to load all of the songs, we will have to implement the index()
method. To do that, add the following code:
index( params ){
return axios.get( 'https://music.com/api/v1/songs', {
params: params
})
},
Remember, we set up Axios to be global!
This method accepts a single parameter which should be a JSON object containing any filters, or ordering data that you wish to send. This variable allows you to pass filters to your resource module in the form of a JSON object that Axios will turn into a query string for your API. Remember, sending a GET request with Axios, the second parameter of the Axios GET request is the configuration. This will build a nice query string to append to your request. Because of these filters, this tends to be the most complicated endpoint to create.
Let's say you wanted to search for an artist and order by newest releases. You'd pass a JSON object like this:
{
"artist": "Red Hot Chili Peppers",
"order_by": "release_date",
"order_direction": "DESC"
}
Your query string will then be formatted like: ?artist=Red%20Hot%20Chili%20Peppers&order_by=release_date&order_direction=DESC
Let's build out the rest of our endpoints for our module and then we can show the power of this module within VueJS.
show
EndpointThe show()
method is very similar to the index()
method since it is a GET
request. However, the show()
method should only return a single resource. In our example, this is a song. To implement this method simply add the following code:
show( id ){
return axios.get( 'https://music.com/api/v1/songs/'+id );
},
Since we are limiting what this endpoint is returning to a single resource, we don't pass a params
variable like we did to the index()
method. The variable id
allows us to load an individual resource based on it's unique identifier.
create
EndpointThis endpoint will handle the creation of a resource on the API, thus using the POST
method. As discussed in the last section, there are two ways to send data to a server with Axios, through JSON and through Form Data. Our API wrapper will account for this by accepting whatever version you throw at it. Let's add the endpoint like this:
create( data ){
return axios.post( 'https://music.com/api/v1/songs', data );
},
The parameter data
will contain either a JSON object or a FormData object depending on if you need to send files. Either one works! When we implement this module in Step 3 & 4 you can see how fluid this will be to submit data to a server.
update
EndpointSimilar to the create
endpoint, the update
endpoint sends data to the API. However, since we are updating a resource, we need an additional parameter of id
to identify the specific resource we are updating. Depending on the use case, you should use PUT
or PATCH
for the method. Let's say we are using PUT
. Our wrapper method should look like this:
update( id, data ){
return axios.put( 'https://music.com/api/v1/songs/'+id, data );
},
We build the URL to update the specific song defined by our id
parameter. Similar to the create
endpoint, the data
parameter can be either JSON or FormData. HOWEVER, if it is FormData, you will have to modify your method in certain circumstances (like with Laravel), to look like this:
update( id, data ){
data._method = 'PUT';
return axios.post( 'https://music.com/api/v1/songs/'+id, data );
},
I know Laravel specifically requires you to POST
any FormData to the server, but if you add _method
and set it to PUT
you can keep your resource controllers standardized and can respond to the request.
delete
EndpointThis is the last endpoint we will be implementing. It simply deletes a resource from the system. The only parameter it accepts is the id
of the resource we wish to delete:
delete( id ){
return axios.delete( 'https://music.com/api/v1/songs/' + id )
}
There we go! This is what our final API Wrapper should look like:
export default {
index( params ){
return axios.get( 'https://music.com/api/v1/songs', {
params: params
})
},
show( id ){
return axios.get( 'https://music.com/api/v1/songs/'+id );
},
update( id, data ){
return axios.put( 'https://music.com/api/v1/songs/'+id, data );
},
create( data ){
return axios.post( 'https://music.com/api/v1/songs', data );
},
delete( id ){
return axios.delete( 'https://music.com/api/v1/songs/' + id )
}
}
Now, let's get to the part where our hard work pays off. Using the module within a VueJS component and Vuex module! You will be able to use these methods anywhere you feel is necessary making the code standardized and extremely re-usable!
Now it's time to reap the rewards of our hard work! We can re-use our module in any component or page within our VueJS App! The API Wrapper comes in handy whenever you need to interface with an API. Sometimes, this could be in a parent page (like a layout) as well where you need to load data globally.
All you need to do inside of your component is include the API module you created. Let's say we have a page that loads all of the songs from our music app by the Red Hot Chili Peppers
. We would have a component that looks like this:
<template>
<div class="songs-page">
</div>
</template>
<script>
import SongsAPI from '../path/to/api/songs.js';
export default {
data(){
return {
songs: []
}
},
mounted(){
SongsAPI.index({
"artist": "Red Hot Chili Peppers",
"order_by": "release_date",
"order_direction": "DESC"
}).then(function( response ){
this.songs = response.data;
}.bind(this));
}
}
</script>
All we needed to do is import
our API module within our component and then call the method in our `
Professional developers choose Server Side Up to ship quality applications without surrendering control. Explore our tools and resources or work directly with us.
We're a community of 3,000+ members help each other level up our development skills.
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.
Be the first to know about our latest releases and product updates.