Working with APIs in Vue.js Applications

ยท

6 min read

Working with APIs in Vue.js Applications

In this article, I share some best practices, tips, and tricks you can apply when consuming APIs in your Vue applications.

After reading this post, you will learn the following:

  • How to structure your app when consuming APIs.

  • How to display a progress bar during API calls.

How to structure your app when consuming APIs

To explain the things I want to share in this article, I have created a simple Restful API that makes post and get requests to /api/posts endpoint which is running on my localhost:3000.

Let's say I want to achieve the following:

  1. Store users' blog posts on my database.
  2. Display all the blog posts on page load.

I could have a text area where users can type their messages and use v-model to create two-way data binding. (Of course, I'm keeping the user interface very minimal). My template and data function could look like this:

1.png

Notice the use of @submit.prevent on the form. The prevent modifier ensures that the page does not reload after the submit button is clicked.

2.png

Let's see the various approach we can take when consuming APIs in a Vue app

All of the approaches require axios for making API calls. So in my terminal, I run yarn add axios or if you prefer NPM, you could run npm install axios.

A. Write the API endpoint inside of the function.

3.png

4.png

The API request failed because of CORS policy limitations. In a nutshell, this is a kind of error that occurs when you try to make API requests to a server running on a different origin. For example, my Vue app is running on localhost:8080. But the Node.js backend where the API code is written is hosted on localhost:3000.

So how can this issue be fixed?

At the root of my Vue app project folder, I create a vue.config.js file (if it does not exist already) and add the following content:

vue-config.png

If you scaffolded your Vue app with Vite.js, then add the following to your vite.config.js file:

vite-config.png

NB: Replace 8080 with the port your vue app is running on. Replace 3000 with the port your backend API is running on.

With this, I am instructing the browser, to redirect (proxy) any HTTP request with a URL that starts with /api to http://localhost:3000

Finally, I update the URL endpoint inside of the function from http://localhost:3000/api/posts to /api/posts.

method.png

Now if I try it again, everything should work just fine.

response.png

And YES it does!

How to view the list of posts on page load

To fetch the list of posts on page load, I could use either the created or mounted lifecycle hooks. For making API calls, I prefer the created hook since it runs before the mounted hook. Hence the API response could return a bit faster.

created.png

v-for.png

Notice how I destructured content, author, and _id from posts. Some Vue devs aren't aware of this. So yea, you can destructure inside a v-for. But if you are not cool with this syntax, you can always write the traditional v-for syntax where you could write v-for="post in posts". And say post.content, post.author, and post._id.

res.png

This approach of consuming API works. But I consider it to be less ideal. Because it violates the DRY (Don't Repeat Yourself) principle of programming. Because each time you want to make an API call, you have to always write the base URL which in this case is /api/posts. Also, you would have to import Axios in every file where an API call is made. Not cool right? ๐Ÿ˜

The next approaches help to provide better alternatives.

B. Use this.$axios instance property.

As an improvement to the previous approach, I can import axios in main.js file and create an axios instance property that can be accessed from any .vue page or component. This solves the problem of importing axios in every file.

$axios.png

Now, I can delete the axios import statement in my component and use this.$axios instead.

this.png

C. Create reusable functions.

This is the approach I mostly use and recommend. It solves the issue of repeating the base URL and also imports axios once.

For this approach, I create a folder in my src directory and name it services. In the services folder, I create a file known as http-client.js. In this file, I import axios and create an axios instance containing the base URL with default headers. Finally, I export the instance.

instance.png

Then, I create a file for every resource I consume. Resources could be posts, comments, users, patient records, etc.

In this example, I have only one resource which is posts. So inside of the services folder, I create a PostsDataService.js file and set up a javascript class containing reusable methods.

class.png

I import the class inside of the components where I want to make API calls and invoke the appropriate functions.

Screenshot 2021-07-22 at 2.30.44 PM.png

Alternatively, if I don't want to use javascript classes, I could refactor the content of PostsDataService.js to be more of a functional programming style using the module design pattern. That means I could write a postsdataService function that contains createPost and getPosts methods. And return these two methods from postsDataService so that they can be publicly available from anywhere in my app.

functional.png

module.png

D. Make API calls inside of Vuex actions

This approach extends the last one. Here, all API calls would be made inside of vuex actions instead of inside components. The javascript class/function created earlier would be imported inside a vuex module, and its functions would be invoked inside vuex actions which would then commit mutations that would update the vuex state. Components would listen for state changes and update the UI accordingly.

This approach is pretty cool and I intend to write a separate post about it later.

How to show a progress bar when making API calls

Wouldn't it be cool to display a progress bar when making an API call? It can give your users a good user experience.

Interestingly, displaying progress bars when making API calls in a Vue app isn't difficult at all.

To accomplish this, you need to install nprogress from NPM and just call the start and done methods. The slightly tricky part is where to call these methods. The easiest way is to call the start method at the beginning of the functions making your API calls ( In this example, that would be the createPost and getPosts methods). But this approach is not efficient as it violates the DRY principle of programming.

So I'm going to show you how to display progress bars for all your API calls without repeating your code.

It basically involves intercepting axios requests and call the start method, and intercept axios response and call the done method.

So I will update my http-client.js file to this: progress.png

Then load the CSS file of the nprogress package inside of App.vue file.

app.png

And that's it! Now, each time an API call is made anywhere in my Vue app (whether it's a post, get, delete, put or patch request), a nice-looking progress bar with a spinner icon will be shown to my users as seen in the screenshots below.

Screenshot 2021-07-24 at 1.40.22 AM.png

Screenshot 2021-07-24 at 1.40.56 AM.png

Screenshot 2021-07-24 at 1.41.44 AM.png

Conclusion In this article, we have looked at various ways to structure a Vue.js app when consuming APIs. Along the way, we saw how to fix CORS errors that could prevent us from successfully making API requests. Finally, you learned how to show a nice-looking progress bar when making API calls by using the nprogress package and intercepting axios requests and responses.

If you have questions or suggestions on how to better structure your app when consuming APIs, you can share your thoughts below. I'd be happy to check them out and give my replies.

ย