Vue.js + Mock API: полная интеграция за 15 минут

← Вернуться к статьям

Введение

Начинаете новый Vue.js проект, но backend еще не готов? Не хотите ждать неделями, пока API будет разработан? В этом туториале вы создадите полноценное Todo приложение на Vue.js 3 с API интеграцией за 15 минут — без единой строки backend кода.

✅ Что вы получите в конце:

💡 Для кого этот туториал:

📋 План действий (15 минут)

Что мы создадим 🎯

Мы создадим классическое Todo приложение с полноценным API. Это идеальный проект для изучения, так как он включает все основные операции:

Функция API Endpoint Метод
Получить все задачи GET /todos Read
Создать задачу POST /todos Create
Обновить задачу PUT /todos/:id Update
Удалить задачу DELETE /todos/:id Delete

Технологический стек

Шаг 1: Setup проекта (2 минуты)

1 Создайте Vue.js приложение с Vite

# Создаем проект
npm create vite@latest todo-app -- --template vue-ts

# Переходим в директорию
cd todo-app

# Устанавливаем зависимости
npm install

# Устанавливаем дополнительные библиотеки
npm install axios pinia @vueuse/core

2 Структура проекта

todo-app/
├── src/
│   ├── api/
│   │   └── todos.ts          # API функции
│   ├── composables/
│   │   └── useTodos.ts       # Vue composable для todos
│   ├── stores/
│   │   └── todos.ts          # Pinia store
│   ├── components/
│   │   ├── TodoList.vue      # Список задач
│   │   ├── TodoItem.vue      # Одна задача
│   │   └── AddTodo.vue       # Форма добавления
│   ├── types/
│   │   └── todo.ts           # TypeScript типы
│   ├── App.vue               # Главный компонент
│   └── main.ts               # Entry point
├── package.json
└── vite.config.ts

Шаг 2: Создание Mock API (3 минуты)

1 Зарегистрируйтесь на LightBox API

Перейдите на lightboxapi.ru и создайте бесплатный аккаунт.

2 Создайте workspace

В dashboard создайте новый workspace с именем todo-app.

3 Настройте endpoints

Endpoint 1: GET /todos
{
  "todos": [
    {
      "id": "1",
      "title": "Изучить Vue 3 Composition API",
      "completed": false,
      "createdAt": "2025-10-22T10:00:00Z"
    },
    {
      "id": "2",
      "title": "Интегрировать Mock API",
      "completed": true,
      "createdAt": "2025-10-22T09:00:00Z"
    }
  ]
}
Endpoint 2: POST /todos
{
  "id": "{randomUUID}",
  "title": "{body.title}",
  "completed": false,
  "createdAt": "{$timestamp}"
}
Endpoint 3: PUT /todos/:id
{
  "id": "{params.id}",
  "title": "{body.title}",
  "completed": "{body.completed}",
  "createdAt": "{existing.createdAt}"
}
Endpoint 4: DELETE /todos/:id
{
  "success": true,
  "message": "Todo deleted"
}

Скопируйте URL вашего Mock API, например: https://lightboxapi.ru/your-workspace

Шаг 3: Настройка HTTP клиента (2 минуты)

1 Создайте TypeScript типы

Файл: src/types/todo.ts

export interface Todo {
  id: string;
  title: string;
  completed: boolean;
  createdAt: string;
}

export interface CreateTodoDto {
  title: string;
}

export interface UpdateTodoDto {
  title?: string;
  completed?: boolean;
}

2 Настройте Axios клиент

Файл: src/api/todos.ts

import axios from 'axios';
import type { Todo, CreateTodoDto, UpdateTodoDto } from '../types/todo';

const API_BASE_URL = import.meta.env.VITE_API_URL || 'https://lightboxapi.ru/your-workspace';

const apiClient = axios.create({
  baseURL: API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

export const todosApi = {
  // Получить все задачи
  async getAll(): Promise {
    const response = await apiClient.get<{ todos: Todo[] }>('/todos');
    return response.data.todos;
  },

  // Создать задачу
  async create(data: CreateTodoDto): Promise {
    const response = await apiClient.post('/todos', data);
    return response.data;
  },

  // Обновить задачу
  async update(id: string, data: UpdateTodoDto): Promise {
    const response = await apiClient.put(`/todos/${id}`, data);
    return response.data;
  },

  // Удалить задачу
  async delete(id: string): Promise {
    await apiClient.delete(`/todos/${id}`);
  },
};

3 Настройте переменные окружения

Файл: .env

VITE_API_URL=https://lightboxapi.ru/your-workspace

Шаг 4: Vue Composables для API (3 минуты)

Vue 3 Composition API позволяет создавать переиспользуемые логические части — composables. Это современный подход для работы с API.

1 Создайте composable для todos

Файл: src/composables/useTodos.ts

import { ref, computed } from 'vue';
import { todosApi } from '../api/todos';
import type { Todo, CreateTodoDto, UpdateTodoDto } from '../types/todo';

export function useTodos() {
  const todos = ref([]);
  const loading = ref(false);
  const error = ref(null);

  // Вычисляемое свойство для количества задач
  const todosCount = computed(() => todos.value.length);
  const completedCount = computed(() =>
    todos.value.filter(t => t.completed).length
  );

  // Загрузить все задачи
  const fetchTodos = async () => {
    loading.value = true;
    error.value = null;
    try {
      todos.value = await todosApi.getAll();
    } catch (err: any) {
      error.value = err.message || 'Ошибка загрузки задач';
      console.error('Error fetching todos:', err);
    } finally {
      loading.value = false;
    }
  };

  // Создать задачу
  const createTodo = async (data: CreateTodoDto) => {
    loading.value = true;
    error.value = null;
    try {
      const newTodo = await todosApi.create(data);
      todos.value.push(newTodo);
      return newTodo;
    } catch (err: any) {
      error.value = err.message || 'Ошибка создания задачи';
      console.error('Error creating todo:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };

  // Обновить задачу
  const updateTodo = async (id: string, data: UpdateTodoDto) => {
    loading.value = true;
    error.value = null;
    try {
      const updated = await todosApi.update(id, data);
      const index = todos.value.findIndex(t => t.id === id);
      if (index !== -1) {
        todos.value[index] = updated;
      }
      return updated;
    } catch (err: any) {
      error.value = err.message || 'Ошибка обновления задачи';
      console.error('Error updating todo:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };

  // Удалить задачу
  const deleteTodo = async (id: string) => {
    loading.value = true;
    error.value = null;
    try {
      await todosApi.delete(id);
      todos.value = todos.value.filter(t => t.id !== id);
    } catch (err: any) {
      error.value = err.message || 'Ошибка удаления задачи';
      console.error('Error deleting todo:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };

  // Переключить статус задачи
  const toggleTodo = async (id: string) => {
    const todo = todos.value.find(t => t.id === id);
    if (todo) {
      await updateTodo(id, { completed: !todo.completed });
    }
  };

  return {
    todos,
    loading,
    error,
    todosCount,
    completedCount,
    fetchTodos,
    createTodo,
    updateTodo,
    deleteTodo,
    toggleTodo,
  };
}

Шаг 5: Pinia Store интеграция (2 минуты)

Pinia — это официальный state management для Vue 3. Он проще Vuex и имеет лучшую TypeScript поддержку. Мы можем использовать store вместо composable, если нужно разделить логику.

1 Настройте Pinia

Файл: src/main.ts

import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';

const app = createApp(App);
app.use(createPinia());
app.mount('#app');

2 Создайте Pinia store (опционально)

Файл: src/stores/todos.ts

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { todosApi } from '../api/todos';
import type { Todo, CreateTodoDto, UpdateTodoDto } from '../types/todo';

export const useTodosStore = defineStore('todos', () => {
  const todos = ref([]);
  const loading = ref(false);
  const error = ref(null);

  const todosCount = computed(() => todos.value.length);
  const completedCount = computed(() =>
    todos.value.filter(t => t.completed).length
  );

  async function fetchTodos() {
    loading.value = true;
    error.value = null;
    try {
      todos.value = await todosApi.getAll();
    } catch (err: any) {
      error.value = err.message || 'Ошибка загрузки задач';
    } finally {
      loading.value = false;
    }
  }

  async function createTodo(data: CreateTodoDto) {
    loading.value = true;
    try {
      const newTodo = await todosApi.create(data);
      todos.value.push(newTodo);
      return newTodo;
    } catch (err: any) {
      error.value = err.message || 'Ошибка создания задачи';
      throw err;
    } finally {
      loading.value = false;
    }
  }

  async function updateTodo(id: string, data: UpdateTodoDto) {
    const updated = await todosApi.update(id, data);
    const index = todos.value.findIndex(t => t.id === id);
    if (index !== -1) {
      todos.value[index] = updated;
    }
    return updated;
  }

  async function deleteTodo(id: string) {
    await todosApi.delete(id);
    todos.value = todos.value.filter(t => t.id !== id);
  }

  async function toggleTodo(id: string) {
    const todo = todos.value.find(t => t.id === id);
    if (todo) {
      await updateTodo(id, { completed: !todo.completed });
    }
  }

  return {
    todos,
    loading,
    error,
    todosCount,
    completedCount,
    fetchTodos,
    createTodo,
    updateTodo,
    deleteTodo,
    toggleTodo,
  };
});

Шаг 6: Создание компонентов (1 минута)

1 Главный компонент App.vue

<template>
  <div class="app">
    <h1>Vue.js Todo App</h1>
    <AddTodo @todo-added="handleTodoAdded" />

    <div v-if="loading">Загрузка...</div>
    <div v-if="error" class="error">{ error }</div>

    <TodoList
      :todos="todos"
      @toggle="handleToggle"
      @delete="handleDelete"
    />

    <div class="stats">
      Всего: { todosCount }, Выполнено: { completedCount }
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue';
import { useTodos } from './composables/useTodos';
import TodoList from './components/TodoList.vue';
import AddTodo from './components/AddTodo.vue';

const {
  todos,
  loading,
  error,
  todosCount,
  completedCount,
  fetchTodos,
  createTodo,
  updateTodo,
  deleteTodo,
  toggleTodo,
} = useTodos();

onMounted(() => {
  fetchTodos();
});

const handleTodoAdded = async (title: string) => {
  await createTodo({ title });
};

const handleToggle = async (id: string) => {
  await toggleTodo(id);
};

const handleDelete = async (id: string) => {
  await deleteTodo(id);
};
</script>

<style scoped>
.app {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
}

.error {
  color: #ef4444;
  padding: 12px;
  background: #fee;
  border-radius: 8px;
  margin: 16px 0;
}

.stats {
  margin-top: 20px;
  padding: 12px;
  background: #f3f4f6;
  border-radius: 8px;
}
</style>

2 Компонент TodoList.vue

<template>
  <ul class="todo-list">
    <TodoItem
      v-for="todo in todos"
      :key="todo.id"
      :todo="todo"
      @toggle="$emit('toggle', todo.id)"
      @delete="$emit('delete', todo.id)"
    />
  </ul>
</template>

<script setup lang="ts">
import TodoItem from './TodoItem.vue';
import type { Todo } from '../types/todo';

defineProps<{ todos: Todo[] }>();
defineEmits<{
  toggle: [id: string];
  delete: [id: string];
}>();
</script>

3 Компонент AddTodo.vue

<template>
  <form @submit.prevent="handleSubmit" class="add-todo">
    <input
      v-model="title"
      type="text"
      placeholder="Добавить задачу..."
      required
    />
    <button type="submit">Добавить</button>
  </form>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const title = ref('');

const emit = defineEmits<{
  todoAdded: [title: string];
}>();

const handleSubmit = () => {
  if (title.value.trim()) {
    emit('todoAdded', title.value);
    title.value = '';
  }
};
</script>

Шаг 7: Deploy на Vercel (1 минута)

1 Подготовьте проект к деплою

# Соберите проект
npm run build

# Проверьте, что dist/ папка создана
ls dist/

2 Deploy на Vercel

  1. Установите Vercel CLI: npm i -g vercel
  2. Выполните: vercel
  3. Следуйте инструкциям
  4. Добавьте переменную окружения VITE_API_URL в настройках проекта

Или используйте GitHub интеграцию Vercel для автоматического деплоя.

Результат 🎉

Поздравляем! Вы создали полноценное Vue.js приложение с API интеграцией за 15 минут. Приложение работает с реальными HTTP запросами к Mock API и готово к работе.

Что мы изучили:

Следующие шаги 🚀

Создайте Mock API за 2 минуты

Не ждите backend — начните разработку Vue.js приложения прямо сейчас с LightBox API. Бесплатный старт для всех разработчиков.

Попробовать бесплатно →
← Вернуться к статьям