← Назад к вопросам
Как настроить взаимодействие с Backend через REST API во Vue приложении?
2.0 Middle🔥 182 комментариев
#Vue.js
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
REST API интеграция во Vue приложении
Визуализирую полный процесс настройки и работы с API в Vue 3 приложении, от конфигурации до практических примеров.
Выбор HTTP клиента
Для Vue есть несколько вариантов:
// 1. Axios (самый популярный)
import axios from 'axios';
// 2. Fetch API (встроен в браузер)
const response = await fetch('/api/users');
const data = await response.json();
// 3. Pinia для состояния + TanStack Query для API
import { useQuery } from '@tanstack/vue-query';
// Я выбираю axios за удобство + TanStack Query за мощность
Шаг 1: Установка и конфигурация Axios
npm install axios
Создаём API клиент в src/lib/api.ts:
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_URL || 'http://localhost:8000',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
});
// Перехватчик для добавления токена
apiClient.interceptors.request.use(
(config) => {
const token = localStorage.getItem('auth_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Перехватчик для обработки ошибок
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Токен истёк, перенаправляем на логин
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default apiClient;
Шаг 2: Создание API сервисов
Организуем API в отдельные сервисы по фичам:
// src/api/users.ts
import apiClient from '@/lib/api';
export const usersApi = {
// GET /users
getUsers: async (page = 1, limit = 10) => {
const { data } = await apiClient.get('/api/v1/users', {
params: { page, limit }
});
return data;
},
// GET /users/:id
getUserById: async (id) => {
const { data } = await apiClient.get(`/api/v1/users/${id}`);
return data;
},
// POST /users
createUser: async (userData) => {
const { data } = await apiClient.post('/api/v1/users', userData);
return data;
},
// PUT /users/:id
updateUser: async (id, userData) => {
const { data } = await apiClient.put(`/api/v1/users/${id}`, userData);
return data;
},
// DELETE /users/:id
deleteUser: async (id) => {
const { data } = await apiClient.delete(`/api/v1/users/${id}`);
return data;
}
};
// src/api/posts.ts
import apiClient from '@/lib/api';
export const postsApi = {
getPosts: async (userId) => {
const { data } = await apiClient.get('/api/v1/posts', {
params: { user_id: userId }
});
return data;
},
createPost: async (postData) => {
const { data } = await apiClient.post('/api/v1/posts', postData);
return data;
}
};
Шаг 3: Composables для логики
Создаём переиспользуемые composables:
// src/composables/useUsers.ts
import { ref, computed } from 'vue';
import { usersApi } from '@/api/users';
export function useUsers() {
const users = ref([]);
const loading = ref(false);
const error = ref(null);
const fetchUsers = async (page = 1, limit = 10) => {
loading.value = true;
error.value = null;
try {
const response = await usersApi.getUsers(page, limit);
users.value = response.data;
} catch (err) {
error.value = err.message;
console.error('Ошибка при загрузке пользователей:', err);
} finally {
loading.value = false;
}
};
const createUser = async (userData) => {
try {
const newUser = await usersApi.createUser(userData);
users.value.push(newUser);
return newUser;
} catch (err) {
error.value = err.message;
throw err;
}
};
const deleteUser = async (id) => {
try {
await usersApi.deleteUser(id);
users.value = users.value.filter(u => u.id !== id);
} catch (err) {
error.value = err.message;
throw err;
}
};
return {
users,
loading,
error,
fetchUsers,
createUser,
deleteUser
};
}
Шаг 4: Использование в компонентах
<!-- src/components/UsersList.vue -->
<template>
<div>
<h1>Список пользователей</h1>
<div v-if="loading" class="loading">Загружаю...</div>
<div v-if="error" class="error">{{ error }}</div>
<ul v-if="users.length">
<li v-for="user in users" :key="user.id">
{{ user.name }} ({{ user.email }})
<button @click="handleDeleteUser(user.id)">Удалить</button>
</li>
</ul>
<div v-else-if="!loading">Пользователей не найдено</div>
<form @submit.prevent="handleCreateUser">
<input v-model="newUserName" placeholder="Имя" required />
<input v-model="newUserEmail" type="email" placeholder="Email" required />
<button type="submit">Добавить пользователя</button>
</form>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useUsers } from '@/composables/useUsers';
const { users, loading, error, fetchUsers, createUser, deleteUser } = useUsers();
const newUserName = ref('');
const newUserEmail = ref('');
onMounted(() => {
fetchUsers();
});
const handleCreateUser = async () => {
try {
await createUser({
name: newUserName.value,
email: newUserEmail.value
});
newUserName.value = '';
newUserEmail.value = '';
} catch (err) {
console.error('Ошибка при создании пользователя:', err);
}
};
const handleDeleteUser = async (id) => {
if (confirm('Вы уверены?')) {
try {
await deleteUser(id);
} catch (err) {
console.error('Ошибка при удалении пользователя:', err);
}
}
};
</script>
Шаг 5: Обработка ошибок
// src/composables/useApi.ts - generic hook
import { ref } from 'vue';
export function useApi(apiFunction) {
const data = ref(null);
const loading = ref(false);
const error = ref(null);
const execute = async (...args) => {
loading.value = true;
error.value = null;
try {
data.value = await apiFunction(...args);
return data.value;
} catch (err) {
error.value = handleError(err);
throw err;
} finally {
loading.value = false;
}
};
return { data, loading, error, execute };
}
function handleError(error) {
if (error.response) {
// Ошибка от сервера (4xx, 5xx)
const { status, data } = error.response;
switch (status) {
case 400:
return 'Неверные данные';
case 401:
return 'Ошибка аутентификации';
case 403:
return 'Доступ запрещен';
case 404:
return 'Ресурс не найден';
case 500:
return 'Ошибка сервера';
default:
return data.message || 'Неизвестная ошибка';
}
} else if (error.request) {
// Запрос был отправлен, но ответа не было
return 'Нет ответа от сервера';
} else {
// Ошибка при создании запроса
return error.message || 'Неизвестная ошибка';
}
}
Шаг 6: Типизация с TypeScript
// src/types/api.ts
export interface User {
id: number;
name: string;
email: string;
created_at: string;
updated_at: string;
}
export interface Post {
id: number;
user_id: number;
title: string;
content: string;
created_at: string;
}
export interface ApiResponse<T> {
status: 'success' | 'error';
data: T;
message?: string;
}
// src/api/users.ts (с типами)
import apiClient from '@/lib/api';
import type { User, ApiResponse } from '@/types/api';
export const usersApi = {
getUsers: async (page = 1, limit = 10): Promise<ApiResponse<User[]>> => {
const { data } = await apiClient.get('/api/v1/users', {
params: { page, limit }
});
return data;
},
getUserById: async (id: number): Promise<ApiResponse<User>> => {
const { data } = await apiClient.get(`/api/v1/users/${id}`);
return data;
},
createUser: async (userData: Omit<User, 'id' | 'created_at' | 'updated_at'>): Promise<ApiResponse<User>> => {
const { data } = await apiClient.post('/api/v1/users', userData);
return data;
}
};
Шаг 7: Кэширование с TanStack Query
npm install @tanstack/vue-query
// src/composables/useUsersQuery.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/vue-query';
import { usersApi } from '@/api/users';
export function useUsersQuery() {
const queryClient = useQueryClient();
// GET запрос с кэшированием
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => usersApi.getUsers(),
staleTime: 1000 * 60 * 5, // 5 минут
});
// POST запрос с инвалидацией кэша
const createMutation = useMutation({
mutationFn: (userData) => usersApi.createUser(userData),
onSuccess: () => {
// Инвалидируем кэш чтобы перезагрузить список
queryClient.invalidateQueries({ queryKey: ['users'] });
}
});
return {
users: data,
isLoading,
error,
createUser: createMutation.mutate
};
}
Шаг 8: Environment переменные
# .env
VUE_APP_API_URL=http://localhost:8000
VUE_APP_API_TIMEOUT=10000
# .env.production
VUE_APP_API_URL=https://api.example.com
// src/lib/api.ts
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_URL,
timeout: parseInt(process.env.VUE_APP_API_TIMEOUT || '10000')
});
Полный пример: список с пагинацией
<template>
<div class="users-container">
<h1>Пользователи (страница {{ currentPage }})</h1>
<div v-if="isLoading" class="spinner">Загружаю...</div>
<div v-if="error" class="error-message">Ошибка: {{ error }}</div>
<div v-if="users" class="users-grid">
<div v-for="user in users.data" :key="user.id" class="user-card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<p class="meta">{{ new Date(user.created_at).toLocaleDateString() }}</p>
</div>
</div>
<div v-if="users" class="pagination">
<button
@click="previousPage"
:disabled="currentPage === 1"
>
Предыдущая
</button>
<span>Страница {{ currentPage }} из {{ users.pages }}</span>
<button
@click="nextPage"
:disabled="currentPage === users.pages"
>
Следующая
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import { usersApi } from '@/api/users';
const currentPage = ref(1);
const limit = 10;
const { data: users, isLoading, error } = useQuery({
queryKey: ['users', currentPage],
queryFn: () => usersApi.getUsers(currentPage.value, limit),
});
const nextPage = () => {
if (users.value?.pages && currentPage.value < users.value.pages) {
currentPage.value++;
}
};
const previousPage = () => {
if (currentPage.value > 1) {
currentPage.value--;
}
};
</script>
<style scoped>
.users-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
margin: 2rem 0;
}
.pagination {
display: flex;
gap: 1rem;
justify-content: center;
margin-top: 2rem;
}
</style>
Итого
Чтобы настроить API во Vue:
- Установить axios
- Создать API клиент с конфигурацией
- Организовать API в сервисы
- Создать composables для логики
- Использовать в компонентах
- Добавить обработку ошибок
- Использовать TypeScript для типизации
- Опционально добавить кэширование (TanStack Query)
Это даёт вам мощную и масштабируемую архитектуру для работы с API.