• Fri, Mar 2026

How to Use Axios with Vue.js for API Calls & Create Data-Driven User Interfaces

How to Use Axios with Vue.js for API Calls & Create Data-Driven User Interfaces

In this hands-on tutorial, we’ll explore how to use Axios with Vue.js to fetch, display, and manage data from APIs. We’ll also dive into building data-driven user interfaces that dynamically adapt to backend responses. Packed with examples, explanations, and best practices, this guide will turn you into a Vue–Axios integration pro.

Introduction: Why Axios with Vue.js?

I still remember my first attempt at calling an API with raw JavaScript’s fetch(). It felt clunky, required extra error handling, and quickly got messy when chaining multiple requests. Enter Axios—a promise-based HTTP client that simplifies API calls, supports interceptors, and works beautifully with Vue.js.

In Vue applications, integrating Axios enables you to fetch data from REST APIs, send POST requests to servers, and build real-time, data-driven interfaces without breaking a sweat.

Step 1: Installing Axios in a Vue Project

Let’s kick things off by installing Axios. If you’re starting fresh with Vue 3, create a project using Vite or Vue CLI:

npm init vue@latest vue-axios-demo
cd vue-axios-demo
npm install
npm install axios
npm run dev

Congratulations! You’re now Axios-ready.

Step 2: Setting Up Axios Globally

While you can import Axios in every component, it’s cleaner to configure it globally. Create an axios.js helper inside a plugins folder:

// src/plugins/axios.js
import axios from "axios";
const apiClient = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com", 
  headers: {
    "Content-Type": "application/json"
  }
});
export default apiClient;

Now you can import apiClient anywhere in your project for consistent API calls.

Step 3: Making Your First GET Request

Let’s fetch posts from a sample API using Axios in a Vue component.

Posts.vue

<template>
  <div>
    <h2>Posts</h2>
    <ul>
      <li v-for="post in posts" :key="post.id">
        {{ post.title }}
      </li>
    </ul>
  </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import apiClient from "../plugins/axios";
const posts = ref([]);
onMounted(async () => {
  try {
    const response = await apiClient.get("/posts");
    posts.value = response.data;
  } catch (error) {
    console.error("Error fetching posts:", error);
  }
});
</script>

Here’s what happens:

  • onMounted triggers the request when the component loads.
  • Axios retrieves posts, and we update the reactive posts array.
  • Vue automatically re-renders the list of posts.

Step 4: Sending Data with POST Requests

Fetching data is fun, but apps often need to send data too. Let’s create a form to add a new post.

NewPost.vue

<template>
  <form @submit.prevent="createPost">
    <input v-model="title" placeholder="Enter title" />
    <textarea v-model="body" placeholder="Enter body"></textarea>
    <button type="submit">Submit</button>
  </form>
</template>
<script setup>
import { ref } from "vue";
import apiClient from "../plugins/axios";
const title = ref("");
const body = ref("");
const createPost = async () => {
  try {
    const response = await apiClient.post("/posts", {
      title: title.value,
      body: body.value,
      userId: 1
    });
    console.log("Post created:", response.data);
  } catch (error) {
    console.error("Error creating post:", error);
  }
};
</script>

With just a few lines of code, you’ve got form submissions working with Axios.

Step 5: Handling Errors Gracefully

Error handling is critical. Axios provides structured error responses, which you can catch and display.

try {
  const response = await apiClient.get("/invalid-endpoint");
} catch (error) {
  if (error.response) {
    console.error("Server responded with:", error.response.data);
  } else if (error.request) {
    console.error("No response received:", error.request);
  } else {
    console.error("Error setting up request:", error.message);
  }
}

Always communicate errors to users clearly—nobody likes a silent failure.

Step 6: Building a Data-Driven User Interface

Now let’s move beyond basic requests and build a UI that updates dynamically based on API responses.

UsersList.vue

<template>
  <div>
    <h2>Users</h2>
    <ul>
      <li v-for="user in users" :key="user.id">
        {{ user.name }} ({{ user.email }})
      </li>
    </ul>
    <button @click="fetchUsers">Reload Users</button>
  </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import apiClient from "../plugins/axios";
const users = ref([]);
const fetchUsers = async () => {
  try {
    const response = await apiClient.get("/users");
    users.value = response.data;
  } catch (error) {
    console.error("Error fetching users:", error);
  }
};
onMounted(fetchUsers);
</script>

This component displays users, and clicking “Reload Users” refetches fresh data—creating a fully data-driven experience.

Step 7: Using Axios Interceptors for Automation

Imagine you need to attach an authentication token to every request. Instead of repeating yourself, use interceptors:

apiClient.interceptors.request.use(config => {
  const token = localStorage.getItem("authToken");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

Now every Axios request automatically carries your token.

Step 8: Best Practices for Vue + Axios

  • Centralize Axios configuration: Use a plugin or composable for consistency.
  • Handle errors gracefully: Always display helpful messages.
  • Keep UI responsive: Show loading spinners while waiting for API calls.
  • Cache or paginate: Optimize large data sets with pagination or local caching.
  • Secure sensitive data: Never hardcode API keys in frontend code.

Step 9: Real-World Case Study – Building a Mini Blog

Let’s combine everything into a blog application with posts and comments.

Blog.vue

<template>
 <div>
  <h1>Mini Blog</h1>
  <div v-for="post in posts" :key="post.id" >
   <h3>{{ post.title }}</h3>
   <p>{{ post.body }}</p>
   <button @click="loadComments(post.id)">View Comments</button>
   <ul v-if="comments[post.id]">
    <li v-for="comment in comments[post.id]" :key="comment.id">
     {{ comment.name }}: {{ comment.body }}
    </li>
   </ul>
  </div>
 </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import apiClient from "../plugins/axios";
const posts = ref([]);
const comments = ref({});
const fetchPosts = async () => {
 const response = await apiClient.get("/posts?_limit=5");
 posts.value = response.data;
};
const loadComments = async (postId) => {
 const response = await apiClient.get(`/posts/${postId}/comments`);
 comments.value[postId] = response.data;
};
onMounted(fetchPosts);
</script>
<style scoped>
.post { margin-bottom: 20px; border-bottom: 1px solid #ccc; padding-bottom: 10px; }
</style>

This app loads posts and allows users to fetch comments dynamically—exactly what a real-world, data-driven Vue interface looks like.

Step 10: Adding a Loading Spinner and Error UI Component

When making API calls, users hate waiting without feedback. A loading spinner gives users a sense of progress, while a dedicated error component communicates what went wrong in a friendly way. Let’s make our app feel more polished and user-friendly.

LoadingSpinner.vue

This reusable component will show a simple animated spinner:

<template>
 <div ></div>
</template>
<style scoped>
.spinner {
 border: 4px solid #f3f3f3;
 border-top: 4px solid #42b983;
 border-radius: 50%;
 width: 40px;
 height: 40px;
 animation: spin 1s linear infinite;
 margin: 20px auto;
}
@keyframes spin {
 0% { transform: rotate(0deg); }
 100% { transform: rotate(360deg); }
}
</style>

ErrorMessage.vue

This component cleanly displays an error message.

<template>
 <div >
  <p>⚠️ {{ message }}</p>
 </div>
</template>
<script setup>
defineProps({
 message: {
  type: String,
  required: true
 }
});
</script>
<style scoped>
.error-message {
 background-color: #ffe5e5;
 color: #d8000c;
 padding: 10px;
 border: 1px solid #d8000c;
 border-radius: 4px;
 margin: 10px 0;
}
</style>

Integrating Spinner and Error in a Data-Driven UI

Now let’s improve our UsersList.vue with loading and error states.

<template>
  <div>
    <h2>Users</h2>
    <LoadingSpinner v-if="loading" />
    <ErrorMessage v-if="error" :message="error" />
    <ul v-if="!loading && !error">
      <li v-for="user in users" :key="user.id">
        {{ user.name }} ({{ user.email }})
      </li>
    </ul>
    <button @click="fetchUsers">Reload Users</button>
  </div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import apiClient from "../plugins/axios";
import LoadingSpinner from "./LoadingSpinner.vue";
import ErrorMessage from "./ErrorMessage.vue";
const users = ref([]);
const loading = ref(false);
const error = ref(null);
const fetchUsers = async () => {
  loading.value = true;
  error.value = null;
  try {
    const response = await apiClient.get("/users");
    users.value = response.data;
  } catch (err) {
    error.value = "Failed to load users. Please try again.";
  } finally {
    loading.value = false;
  }
};
onMounted(fetchUsers);
</script>

Here’s how this improves UX:

  • While waiting, the spinner is shown.
  • If an error occurs, the red error box is displayed.
  • On success, the users list renders normally.

Conclusion

We’ve covered everything from installing Axios to building full data-driven UIs in Vue. Along the way, you learned how to make GET and POST requests, handle errors, use interceptors, and follow best practices for building scalable, API-driven applications.You now have:

  • API calls with Axios (GET, POST, error handling).
  • Dynamic, data-driven Vue interfaces.
  • Reusable components for loading and error states.
  • Best practices like interceptors and clean code organization.

The next time someone asks, “How do you connect Vue.js to an API?”, you’ll confidently say: “With Axios, of course!” 🚀

This website uses cookies to enhance your browsing experience. By continuing to use this site, you consent to the use of cookies. Please review our Privacy Policy for more information on how we handle your data. Cookie Policy