Post

BootCamp Tutorial 4: Vue.js Advanced API Integration with Role-Based Access

πŸ“Œ Learning Objectives

In this tutorial, we will integrate API endpoints with Vue.js while maintaining separation of concerns by keeping API calls modular. You will learn: βœ… Fetching and displaying tasks
βœ… Managing users and approving/rejecting them
βœ… Updating and deleting tasks
βœ… Assigning tasks to users
βœ… Displaying statistics for Admin & Manager

By the end, you will have a complete Vue.js dashboard to manage tasks & users efficiently.


πŸ“Œ Setting Up API Handling in Vue

Before creating pages, let’s set up a file to handle API interactions in a structured way.

πŸ“‚ src/services/api.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import axios from "axios";

const API_URL = "http://127.0.0.1:5000";
const token = localStorage.getItem("token");

const api = axios.create({
  baseURL: API_URL,
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
  },
});

export const fetchTasks = () => api.get("/tasks");
export const fetchTaskById = (taskId) => api.get(`/task/${taskId}`);
export const updateTask = (taskId, data) => api.put(`/task/${taskId}`, data);
export const deleteTask = (taskId) => api.delete(`/task/${taskId}`);
export const fetchPendingUsers = () => api.get("/users/pending");
export const approveUser = (userId) => api.put(`/users/${userId}/approve`);
export const rejectUser = (userId) => api.delete(`/users/${userId}/reject`);
export const assignTask = (taskId, userId) => api.put(`/task/${taskId}/assign`, { user_id: userId });
export const fetchStats = () => api.get("/stats");

export default api;

1️⃣ Fetching & Displaying Tasks

πŸ“‚ src/views/TaskList.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<template>
  <div>
    <h2>Task Management</h2>
    <button @click="fetchTaskList">Refresh</button>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Title</th>
          <th>Description</th>
          <th>Status</th>
          <th>Deadline</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="task in tasks" :key="task.id">
          <td>{{ task.id }}</td>
          <td>{{ task.title }}</td>
          <td>{{ task.description || 'N/A' }}</td>
          <td>{{ task.status }}</td>
          <td>{{ task.deadline || 'No deadline' }}</td>
          <td>
            <button @click="editTask(task)">Edit</button>
            <button @click="deleteTaskById(task.id)">Delete</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
import { fetchTasks, deleteTask } from "@/services/api.js";

export default {
  data() {
    return {
      tasks: [],
    };
  },
  methods: {
    async fetchTaskList() {
      const response = await fetchTasks();
      this.tasks = response.data;
    },
    async deleteTaskById(taskId) {
      if (confirm("Are you sure you want to delete this task?")) {
        await deleteTask(taskId);
        this.fetchTaskList();
      }
    },
    editTask(task) {
      this.$router.push({ name: "EditTask", params: { taskId: task.id } });
    },
  },
  mounted() {
    this.fetchTaskList();
  },
};
</script>

2️⃣ Editing Tasks

πŸ“‚ src/views/EditTask.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<template>
  <div>
    <h2>Edit Task</h2>
    <form @submit.prevent="updateTaskData">
      <label>Title:</label>
      <input v-model="task.title" required />
      <label>Description:</label>
      <input v-model="task.description" />
      <label>Status:</label>
      <select v-model="task.status">
        <option>pending</option>
        <option>in-progress</option>
        <option>completed</option>
      </select>
      <button type="submit">Update Task</button>
    </form>
  </div>
</template>

<script>
import { fetchTaskById, updateTask } from "@/services/api.js";

export default {
  data() {
    return {
      task: {
        title: "",
        description: "",
        status: "pending",
      },
    };
  },
  async mounted() {
    const taskId = this.$route.params.taskId;
    const response = await fetchTaskById(taskId);
    this.task = response.data;
  },
  methods: {
    async updateTaskData() {
      await updateTask(this.$route.params.taskId, this.task);
      this.$router.push("/tasks");
    },
  },
};
</script>

3️⃣ User Approvals

πŸ“‚ src/views/UserApproval.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<template>
  <div>
    <h2>Pending User Approvals</h2>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Username</th>
          <th>Email</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="user in pendingUsers" :key="user.id">
          <td>{{ user.id }}</td>
          <td>{{ user.username }}</td>
          <td>{{ user.email }}</td>
          <td>
            <button @click="approveUserById(user.id)">Approve</button>
            <button @click="rejectUserById(user.id)">Reject</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
import { fetchPendingUsers, approveUser, rejectUser } from "@/services/api.js";

export default {
  data() {
    return {
      pendingUsers: [],
    };
  },
  async mounted() {
    const response = await fetchPendingUsers();
    this.pendingUsers = response.data;
  },
  methods: {
    async approveUserById(userId) {
      await approveUser(userId);
      this.fetchPendingUsers();
    },
    async rejectUserById(userId) {
      await rejectUser(userId);
      this.fetchPendingUsers();
    },
  },
};
</script>

4️⃣ Assigning Tasks

πŸ“‚ src/views/AssignTask.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
  <div>
    <h2>Assign Task</h2>
    <label>Select User:</label>
    <select v-model="selectedUser">
      <option v-for="user in users" :key="user.id" :value="user.id">
        {{ user.username }}
      </option>
    </select>
    <button @click="assignTaskToUser">Assign</button>
  </div>
</template>

<script>
import { assignTask, fetchPendingUsers } from "@/services/api.js";

export default {
  data() {
    return {
      users: [],
      selectedUser: null,
    };
  },
  async mounted() {
    const response = await fetchPendingUsers();
    this.users = response.data;
  },
  methods: {
    async assignTaskToUser() {
      await assignTask(this.$route.params.taskId, this.selectedUser);
      alert("Task Assigned!");
    },
  },
};
</script>

5️⃣ Fetching System Statistics

πŸ“‚ src/views/Stats.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
  <div>
    <h2>System Statistics</h2>
    <p>Total Users: {{ stats.total_users }}</p>
    <p>Total Tasks: {{ stats.total_tasks }}</p>
    <p>Completed Tasks: {{ stats.completed_tasks }}</p>
  </div>
</template>

<script>
import { fetchStats } from "@/services/api.js";

export default {
  data() {
    return {
      stats: {},
    };
  },
  async mounted() {
    const response = await fetchStats();
    this.stats = response.data;
  },
};
</script>

🎯 Summary

  • πŸ”₯ Task Management (List, Edit, Delete, Assign)
  • βœ… User Approvals (Approve/Reject)
  • πŸ“Š Fetching Statistics
  • πŸ› οΈ Role-Based API Handling

This completes our Vue.js API Integration with Role-Based Access! πŸš€

This post is licensed under CC BY 4.0 by the author.