Глава 6.1: Соединение FastAPI с фронтендом
Время изучения: 30 минут
1. Возвращение к "гипердвигателю": Сравнение протоколов
В прошлой главе мы состыковали наш ЦУП (фронтенд) с "МКС" (Laravel API). Теперь мы вернемся к нашему сверхсветовому истребителю (FastAPI) и проведем ту же операцию.
Цель этой главы — не просто повторить действия, а сравнить два подхода. Это как если бы один и тот же корабль Dragon сначала стыковался с МКС, а потом с китайской станцией "Тяньгун". Стыковочный узел тот же (REST), но могут быть нюансы в процедурах и расположении портов.
💡 Космическая аналогия:
Процесс одинаков: подлететь, выровняться, состыковаться. Но для "МКС" нужно было использовать порт
/api/planets
, а для "Тяньгун" — порт/spaceships
. Наш оператор в ЦУПе должен знать эти детали, чтобы миссия прошла успешно.
2. Подготовка "истребителя" (FastAPI) к стыковке
Мы уже делали это в Главе 4.2, но давайте убедимся, что все на месте.
Шаг 1: Запускаем сервер FastAPI
- Остановите сервер Laravel, если он запущен (чтобы не было конфликта портов).
- Откройте терминал в папке вашего FastAPI-проекта.
-
Активируйте виртуальное окружение:
- Windows:
.\venv\Scripts\Activate.ps1
- macOS / Linux:
source venv/bin/activate
- Windows:
-
Запустите сервер:
Сервер будет доступен по адресуhttp://127.0.0.1:8000
.
Шаг 2: Проверяем настройки CORS в main.py
Убедитесь, что в вашем FastAPI-проекте есть настроенный CORSMiddleware
, который мы добавили ранее. Он должен разрешать запросы с адреса вашего фронтенда.
# main.py
from fastapi.middleware.cors import CORSMiddleware
# ...
origins = [
"http://127.0.0.1:5500", # Адрес Live Server
"null", # Для file:///
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ...
3. Перенастройка "антенны" ЦУПа обратно на FastAPI
Теперь самое интересное — минимальные изменения, которые нужно внести в наш JavaScript, чтобы он снова работал с FastAPI.
Шаг 1: Меняем базовый URL
Откройте api.js
и верните API_BASE_URL
к его первоначальному значению.
// api.js
// Указываем URL нашего FastAPI API
const API_BASE_URL = 'http://127.0.0.1:8000'; // <-- Без /api!
// ... остальной код apiRequest ...
Шаг 2: Адаптация к структуре ответа FastAPI
Вспомним, что наш GET /spaceships
в FastAPI возвращает простой массив, а не объект с пагинацией. Это значит, что нам нужно вернуть код fetchAndDisplayFleet
к его первоначальному виду.
Измените функцию fetchAndDisplayFleet
в app.js
:
// app.js
async function fetchAndDisplayFleet() {
try {
fleetListContainer.innerHTML = '<p>Загрузка телеметрии от FastAPI...</p>';
const ships = await apiRequest('/spaceships'); // <-- Запрос на /spaceships
// В FastAPI у нас простой массив, поэтому ключ .data не нужен!
fleetListContainer.innerHTML = '';
if (ships.length === 0) {
fleetListContainer.innerHTML = '<p>В реестре нет аппаратов.</p>';
return;
}
ships.forEach(ship => {
// Возвращаем нашу оригинальную функцию для создания карточек
const card = createShipCard(ship);
fleetListContainer.appendChild(card);
});
} catch (error) {
fleetListContainer.innerHTML = `<p style="color: #ff6b6b;">Ошибка загрузки флота: ${error.message}</p>`;
}
}
// Оригинальная функция для создания карточек кораблей
function createShipCard(ship) {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<h3>${ship.name} (ID: ${ship.id})</h3>
<p>Тип: ${ship.type}</p>
<p>Год запуска: ${ship.launch_year}</p>
<p>Статус: ${ship.status}</p>
<div class="card-actions">
<button class="edit-btn" data-ship-id="${ship.id}">Изменить</button>
<button class="delete-btn" data-ship-id="${ship.id}">Списать</button>
</div>
`;
return card;
}
Шаг 3: Проверка CRUD-операций
Поскольку наши Pydantic-модели в FastAPI и поля в HTML-форме совпадают (name
, type
, launch_year
, status
), функции handleSaveShip
и handleDeleteShip
должны заработать без изменений, так как они уже нацелены на эндпоинт /spaceships
.
4. Итоги сравнения: Что это значит для фронтенд-разработчика?
- Универсальность REST: Вы наглядно убедились, что для фронтенда не имеет значения, на чем написан бэкенд (PHP/Laravel или Python/FastAPI), если он следует принципам REST.
- Важность документации: Основные отличия заключались в URL эндпоинтов и структуре JSON-ответов. Это именно то, что должно быть описано в документации API. Без нее фронтенд-разработчик будет работать "вслепую".
- Гибкость фронтенда: Ваш JavaScript-код должен быть достаточно гибким, чтобы легко адаптироваться к разным форматам данных (например, проверять, есть ли ключ
data
, или это просто массив).
Вывод: Навык работы с REST API — это универсальный ключ, который открывает двери к взаимодействию с любым современным бэкендом.
Квиз для закрепления
🚀 Итог главы:
Вы успешно переключили "протоколы связи" вашего ЦУПа и на практике сравнили работу с двумя разными бэкенд-системами.
- ✅ Вы закрепили навык настройки
API_BASE_URL
для переключения между серверами. - ✅ Вы поняли, как важна структура ответа (
data
vs простой массив) и как адаптировать к ней фронтенд. - ✅ Вы осознали, что хороший фронтенд-разработчик должен быть готов к работе с любым RESTful API, внимательно изучив его документацию.
Навык универсальной стыковки получен! Теперь, когда мы умеем настраивать базовую связь, пора поговорить о более сложных протоколах — CORS, аутентификации и безопасности.
📌 Проверка:
- Убедитесь, что ваш FastAPI-сервер запущен.
- Убедитесь, что вы вернули
API_BASE_URL
и логику обработки ответа вapp.js
к варианту для FastAPI.- Проверьте, что ваш фронтенд снова корректно выполняет все CRUD-операции с FastAPI-бэкендом.
⚠️ Если ошибки:
- CORS error: Убедитесь, что FastAPI-сервер запущен с правильными настройками CORS.
- Ошибка
Cannot read properties of undefined (reading 'length')
: Возможно, вы забыли убрать обращение к.data
изresponseData
.- 404 Not Found: Проверьте
API_BASE_URL
— у FastAPI нет префикса/api
.