Current Backend API Calling Stack
Frontend Structure (high-level)
src/main.js: Vue app bootstrap + router.
src/views/: page-level views (e.g. Home.vue, Login.vue, CourseDetail.vue).
src/components/: reusable UI components.
src/composables/: reusable state/data hooks (e.g. useAuth, useCourses, useReviews).
src/utils/: small utilities (cookies, auth flow helpers, sanitization).
Where API calls currently live
There is no single centralized API client; calls are spread across:
src/utils/auth.js (auth endpoints)
src/utils/api.js (auth status check)
src/composables/useCourses.js (course list + departments)
src/composables/useReviews.js (review CRUD + voting)
src/views/Home.vue (landing stats)
src/views/CourseDetail.vue (course detail fetch)
src/views/CourseReviewSearch.vue (review search fetch)
src/composables/useAuth.js (logout)
The New Architecture Overview (Layered)
src/api/client.js (The Engine): Centralized Axios instance with interceptors (Base URL, Auth headers).
src/api/modules/*.js (The Order Desk): Pure functions that define specific endpoint paths (No logic, just URLs).
src/composables/use*.js (The Waiter): Manages reactive state (loading, data, error) and calls the API modules.
src/views/*.vue (The Diner): The UI that just displays data and triggers actions.
Step 1: The Base Client (src/api/client.js)
Centralize your Axios logic here.
// src/api/client.js
import axios from 'axios';
const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL, // Use the env variable we discussed!
timeout: 10000,
headers: { 'Content-Type': 'application/json' }
});
// Request Interceptor: Automatically attach Token to every request
// Response Interceptor: Global Error Handling (e.g., **redirect to login on 401 and 403**)
export default apiClient;
Step 2: API Modules (src/api/modules/)
Group your endpoints by domain. This replaces the messy utils/api.js.
src/api/modules/courses.js
export const getCourseDetail = (id) => {
return apiClient.get(`/courses/${id}/`);
};
src/api/modules/auth.js
export const login = (credentials) => {
return apiClient.post('/auth/login/', credentials);
};
Step 3: Composables (src/composables/)
Keep your UI clean by putting data-fetching logic here.
src/composables/useCourses.js
import { ref } from 'vue';
import { getCourses } from '@/api/modules/courses';
export function useCourses() {
const courses = ref([]);
const isLoading = ref(false);
const error = ref(null);
const fetchCourses = async (searchParams) => {
isLoading.value = true;
try {
const response = await getCourses(searchParams);
courses.value = response.data;
} catch (err) {
error.value = err.message;
} finally {
isLoading.value = false;
}
};
return { courses, isLoading, error, fetchCourses };
}
Step 4: The View Layer (src/views/Home.vue)
The view now knows nothing about Axios or URLs. It only knows about the Composable.
<script setup>
const { courses, isLoading, error, fetchCourses } = useCourses();
onMounted(() => {
fetchCourses(); // Just call the function!
});
</script>
Summary of the "Clean" Directory Structure
src/
|-- api/ <-- NEW: API Central Command
| |-- client.js <-- Axios Instance + Interceptors
| |-- modules/ <-- Endpoint definitions
| |-- auth.js <-- login, verifyCaptcha
| |-- courses.js <-- list, detail
| |-- reviews.js <-- CRUD
|-- composables/ <-- Logic & State
| |-- useAuth.js <-- uses api/modules/auth.js
| |-- useCourses.js <-- uses api/modules/courses.js
|-- views/ <-- UI Pages
| |-- Home.vue <-- uses useCourses.js
Why this fixes your problems:
- Centralized Auth: Token injection happens in
client.js once. No more manual headers in useCourses.js.
- No Duplicate Calls: If
CourseDetail.vue and useReviews.js both need course data, they call the same api/modules/courses.js.
- Environment Agnostic: If your backend URL changes, you change exactly one line in
.env.
- Testable: You can test
api/modules/courses.js without even running the Vue UI.
- Base Interceptor: handle header, error handling easily
Current Backend API Calling Stack
Frontend Structure (high-level)
src/main.js: Vue app bootstrap + router.src/views/: page-level views (e.g.Home.vue,Login.vue,CourseDetail.vue).src/components/: reusable UI components.src/composables/: reusable state/data hooks (e.g.useAuth,useCourses,useReviews).src/utils/: small utilities (cookies, auth flow helpers, sanitization).Where API calls currently live
There is no single centralized API client; calls are spread across:
src/utils/auth.js(auth endpoints)src/utils/api.js(auth status check)src/composables/useCourses.js(course list + departments)src/composables/useReviews.js(review CRUD + voting)src/views/Home.vue(landing stats)src/views/CourseDetail.vue(course detail fetch)src/views/CourseReviewSearch.vue(review search fetch)src/composables/useAuth.js(logout)The New Architecture Overview (Layered)
src/api/client.js(The Engine): Centralized Axios instance with interceptors (Base URL, Auth headers).src/api/modules/*.js(The Order Desk): Pure functions that define specific endpoint paths (No logic, just URLs).src/composables/use*.js(The Waiter): Manages reactive state (loading,data,error) and calls the API modules.src/views/*.vue(The Diner): The UI that just displays data and triggers actions.Step 1: The Base Client (
src/api/client.js)Centralize your Axios logic here.
Step 2: API Modules (
src/api/modules/)Group your endpoints by domain. This replaces the messy
utils/api.js.src/api/modules/courses.jssrc/api/modules/auth.jsStep 3: Composables (
src/composables/)Keep your UI clean by putting data-fetching logic here.
src/composables/useCourses.jsStep 4: The View Layer (
src/views/Home.vue)The view now knows nothing about Axios or URLs. It only knows about the Composable.
Summary of the "Clean" Directory Structure
Why this fixes your problems:
client.jsonce. No more manual headers inuseCourses.js.CourseDetail.vueanduseReviews.jsboth need course data, they call the sameapi/modules/courses.js..env.api/modules/courses.jswithout even running the Vue UI.