Using REST API with Vue
March 7, 2025 ยท AI Conversations
—
### **Steps to Use REST API in Vue.js (with Axios)**
#### **1. Install Axios (if not installed)**
Since you're using Yarn, run:
yarn add axios
Or with npm:
npm install axios
—
#### **2. Make an API Request in Vue Component**
Here's an example of fetching data from an API in a Vue 3 component:
<script setup>
import { ref, onMounted } from "vue";
import axios from "axios";
const posts = ref([]);
const loading = ref(true);
const error = ref(null);
const fetchPosts = async () => {
try {
const response = await axios.get("https://jsonplaceholder.typicode.com/posts");
posts.value = response.data;
} catch (err) {
error.value = "Error fetching posts";
} finally {
loading.value = false;
}
};
onMounted(fetchPosts);
</script>
<template>
<div>
<h2>Posts</h2>
<p v-if="loading">Loading...</p>
<p v-if="error">{{ error }}</p>
<ul v-if="!loading && !error">
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
—
#### **3. Make a POST Request**
To send data to an API:
<script setup>
import { ref } from "vue";
import axios from "axios";
const newPost = ref({
title: "",
body: "",
});
const submitPost = async () => {
try {
const response = await axios.post("https://jsonplaceholder.typicode.com/posts", newPost.value);
console.log("Post created:", response.data);
} catch (err) {
console.error("Error creating post:", err);
}
};
</script>
<template>
<form @submit.prevent="submitPost">
<input v-model="newPost.title" placeholder="Title" required />
<textarea v-model="newPost.body" placeholder="Body" required></textarea>
<button type="submit">Submit</button>
</form>
</template>
—
### **4. Create an Axios Instance (For Global Use)**
Instead of calling `axios.get()` directly everywhere, you can create a reusable instance:
import axios from "axios";
const api = axios.create({
baseURL: "https://jsonplaceholder.typicode.com",
headers: {
"Content-Type": "application/json",
},
});
export default api;
Then use it in your components:
import api from "@/api"; // Adjust the path accordingly
api.get("/posts").then(response => {
console.log(response.data);
});
—
### **5. Handle Authentication (Example: Bearer Token)**
If your API requires authentication:
const api = axios.create({
baseURL: "https://api.example.com",
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
—
Let me know if you need help integrating this with your Laravel backend! ๐
—
### **Updated Vue Component with Post Links**
<script setup>
import { ref, onMounted } from "vue";
import axios from "axios";
const posts = ref([]);
const loading = ref(true);
const error = ref(null);
const fetchPosts = async () => {
try {
const response = await axios.get("https://jsonplaceholder.typicode.com/posts");
posts.value = response.data;
} catch (err) {
error.value = "Error fetching posts";
} finally {
loading.value = false;
}
};
onMounted(fetchPosts);
</script>
<template>
<div>
<h2>Posts</h2>
<p v-if="loading">Loading...</p>
<p v-if="error">{{ error }}</p>
<ul v-if="!loading && !error">
<li v-for="post in posts" :key="post.id">
<a :href="`/posts/${post.id}`" target="_blank">{{ post.title }}</a>
</li>
</ul>
</div>
</template>
—
### **Explanation:**
– The “ tag dynamically generates a link using `:href="`/posts/${post.id}`"`.
– Clicking the link will navigate to `/posts/{id}`, assuming you have a route set up for post details.
– `target="_blank"` opens the link in a new tab.
—
### **Bonus: Using Vue Router for Navigation**
If you're using **Vue Router**, update the links like this:
<RouterLink :to="`/posts/${post.id}`">{{ post.title }}</RouterLink>
And define a route in your `router.js`:
{
path: "/posts/:id",
name: "PostDetails",
component: () => import("@/views/PostDetails.vue")
}
This way, clicking a post title navigates within the Vue app without a full page reload. ๐
—
### **Example: Linking to an External URL**
Modify the Vue component to use an **external link**:
<script setup>
import { ref, onMounted } from "vue";
import axios from "axios";
const posts = ref([]);
const loading = ref(true);
const error = ref(null);
const fetchPosts = async () => {
try {
const response = await axios.get("https://jsonplaceholder.typicode.com/posts");
posts.value = response.data.map(post => ({
...post,
url: `https://example.com/posts/${post.id}`, // Replace with actual external URL logic
}));
} catch (err) {
error.value = "Error fetching posts";
} finally {
loading.value = false;
}
};
onMounted(fetchPosts);
</script>
<template>
<div>
<h2>Posts</h2>
<p v-if="loading">Loading...</p>
<p v-if="error">{{ error }}</p>
<ul v-if="!loading && !error">
<li v-for="post in posts" :key="post.id">
<a :href="post.url" target="_blank" rel="noopener noreferrer">{{ post.title }}</a>
</li>
</ul>
</div>
</template>
—
### **Key Changes:**
1. **Dynamically generate the external URL** (e.g., `https://example.com/posts/${post.id}`).
2. **Use “ with `target="_blank"`** to open the link in a new tab.
3. **Add `rel="noopener noreferrer"`** for security when opening external links.
#### **If Your API Provides the External URL**
If your API response already includes an external URL (e.g., `post.external_url`), modify the mapping:
posts.value = response.data.map(post => ({
...post,
url: post.external_url, // Use the actual external URL from API
}));
This way, your Vue app dynamically links to external posts without hardcoding URLs. ๐
—
### **Updated Vue Component with Excerpt Limiting**
<script setup>
import { ref, onMounted, computed } from "vue";
import axios from "axios";
const posts = ref([]);
const loading = ref(true);
const error = ref(null);
const fetchPosts = async () => {
try {
const response = await axios.get("https://jsonplaceholder.typicode.com/posts");
posts.value = response.data.map(post => ({
...post,
excerpt: post.body.length > 100 ? post.body.substring(0, 100) + "..." : post.body, // Limit to 100 characters
url: `https://example.com/posts/${post.id}`, // Replace with actual external URL logic
}));
} catch (err) {
error.value = "Error fetching posts";
} finally {
loading.value = false;
}
};
onMounted(fetchPosts);
</script>
<template>
<div>
<h2>Posts</h2>
<p v-if="loading">Loading...</p>
<p v-if="error">{{ error }}</p>
<ul v-if="!loading && !error">
<li v-for="post in posts" :key="post.id">
<h3>
<a :href="post.url" target="_blank" rel="noopener noreferrer">{{ post.title }}</a>
</h3>
<p>{{ post.excerpt }}</p>
</li>
</ul>
</div>
</template>
—
### **Key Changes:**
1. **Added an excerpt property in `map()`**:
– Limits the body to 100 characters.
– Adds `"…"` if the text is longer.
2. **Displays the excerpt in `{{ post.excerpt }}`**.
This ensures your post descriptions stay concise while linking to full content. ๐