Глава 3.4: CRUD операции для космических аппаратов
Время изучения: 1 час
1. CRUD: Полный цикл управления космической миссией
До сих пор мы только читали данные (Read
). Но настоящий Центр Управления Полетами должен уметь всё:
- Create (Создать): Запустить новый спутник на орбиту.
- Read (Прочитать): Запросить статус существующего аппарата.
- Update (Обновить): Скорректировать орбиту или обновить ПО.
- Delete (Удалить): Свести с орбиты старый спутник.
Эти четыре операции — CRUD — составляют основу большинства API. В этой главе мы реализуем полный цикл для управления нашим флотом.
2. Create: Запуск нового корабля (POST)
Чтобы создать новый космический аппарат, мы будем использовать метод POST
. Данные для нового корабля будут передаваться в теле запроса в формате JSON.
Шаг 1: Создаем новую Pydantic-модель для входящих данных
Почему нужна новая модель? Потому что при создании корабля мы не знаем его id
— его должен присвоить сервер.
Добавьте эту модель в main.py
:
# main.py
from pydantic import BaseModel, Field
class SpaceshipCreate(BaseModel):
"""Модель для создания нового корабля (без ID)."""
name: str = Field(..., min_length=3, max_length=50)
type: str
launch_year: int = Field(..., gt=1950)
status: str
Spaceship
, но она будет использоваться для валидации входящих данных.
Шаг 2: Реализуем endpoint POST /spaceships
# main.py
import random # Добавьте этот импорт вверху файла
# ... остальной код ...
@app.post("/spaceships", response_model=Spaceship, status_code=201)
def create_spaceship(ship: SpaceshipCreate):
"""
Добавляет новый космический аппарат в реестр.
"""
# Генерируем новый уникальный ID для корабля
new_id = max(db_spaceships.keys() or [0]) + 1
# Создаем объект корабля, соответствующий полной модели Spaceship
new_ship = Spaceship(id=new_id, **ship.dict())
# Сохраняем в нашей "базе данных"
db_spaceships[new_id] = new_ship.dict()
return new_ship
@app.post(...)
: Используем декоратор дляPOST
-запросов.status_code=201
: Указываем, что при успешном создании нужно возвращать статус201 Created
.ship: SpaceshipCreate
: Вот она, магия! FastAPI автоматически возьмет тело запроса (JSON), провалидирует его по моделиSpaceshipCreate
и передаст в функцию как объектship
.new_id = ...
: Простая логика для генерации нового ID.**ship.dict()
: Мы "распаковываем" данные из принятой моделиship
в нашу полную модель.response_model=Spaceship
: Ответ будет соответствовать полной модели, включаяid
.
3. Update: Коррекция курса (PUT)
Для полного обновления существующего ресурса используется метод PUT
.
Реализуем endpoint PUT /spaceships/{ship_id}
:
# main.py
from fastapi import FastAPI, HTTPException # Обновите импорт
# ... остальной код ...
@app.put("/spaceships/{ship_id}", response_model=Spaceship)
def update_spaceship(ship_id: int, ship_update: SpaceshipCreate):
"""
Полностью обновляет данные о космическом аппарате.
"""
if ship_id not in db_spaceships:
raise HTTPException(status_code=404, detail="Космический аппарат не найден")
updated_ship = Spaceship(id=ship_id, **ship_update.dict())
db_spaceships[ship_id] = updated_ship.dict()
return updated_ship
ship_update: SpaceshipCreate
: Мы снова используем нашу модель для валидации входящих данных.HTTPException
: Если корабль с такимid
не найден, мы "выбрасываем" стандартное исключение FastAPI, которое превратится в красивый JSON-ответ с кодом404
.
4. Delete: Сход с орбиты (DELETE)
Для удаления ресурса используется метод DELETE
. Обычно такой endpoint не возвращает тело ответа.
Реализуем endpoint DELETE /spaceships/{ship_id}
:
# main.py
from fastapi import FastAPI, HTTPException, Response, status # Обновите импорт
# ... остальной код ...
@app.delete("/spaceships/{ship_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_spaceship(ship_id: int):
"""
Удаляет космический аппарат из реестра.
"""
if ship_id not in db_spaceships:
raise HTTPException(status_code=404, detail="Космический аппарат не найден")
del db_spaceships[ship_id]
# Возвращаем пустой ответ со статусом 204
return Response(status_code=status.HTTP_204_NO_CONTENT)
status_code=status.HTTP_204_NO_CONTENT
: Мы явно указываем статус204 No Content
.del db_spaceships[ship_id]
: Удаляем запись из нашего словаря.return Response(...)
: Возвращаем пустой ответ, так как клиенту не нужны данные об удаленном объекте.
5. Тестирование полного цикла в /docs
Ваш uvicorn
должен был перезагрузиться.
- Откройте
http://127.0.0.1:8000/docs
. Теперь у вас полный набор CRUD-операций! - POST: Раскройте эндпоинт
POST /spaceships
, нажмите "Try it out", заполните JSON-тело (например, создайте "James Webb Telescope") и нажмите "Execute". Вы должны получить ответ201
с данными нового телескопа. - GET: Теперь выполните
GET /spaceships
. В списке должен появиться ваш новый телескоп. - PUT: Используйте ID нового телескопа, чтобы обновить его данные через
PUT /spaceships/{ship_id}
. Например, измените его статус. - DELETE: Используйте тот же ID, чтобы удалить телескоп через
DELETE /spaceships/{ship_id}
. Вы должны получить пустой ответ со статусом204
. - Проверка: Снова выполните
GET /spaceships
, чтобы убедиться, что телескоп удален из списка.
Квиз для закрепления
🚀 Итог главы:
Вы реализовали полный CRUD-цикл и превратили ваше API из простого "информационного табло" в полноценный Центр Управления Флотом!
- ✅ Create:
POST /spaceships
для запуска новых аппаратов. - ✅ Read:
GET /spaceships
иGET /spaceships/{id}
для получения данных. - ✅ Update:
PUT /spaceships/{id}
для обновления миссий. - ✅ Delete:
DELETE /spaceships/{id}
для списания аппаратов.
Ваш флот под полным контролем! В следующей главе мы увидим, как FastAPI автоматически создал для нас подробную "инструкцию по эксплуатации" — интерактивную документацию Swagger.
📌 Проверка:
- Все 5 эндпоинтов (
GET
(2),POST
,PUT
,DELETE
) видны и работают в/docs
.- Вы можете успешно создать, прочитать, обновить и удалить ресурс.
- При запросе несуществующего ID возвращается ошибка
404
.⚠️ Если ошибки:
NameError
: Проверьте, что вы импортировалиHTTPException
,Response
,status
.KeyError
: Вероятно, вы пытаетесь получить доступ к ID, который уже удален.- Неправильная работа
PUT
илиPOST
: Убедитесь, что вы используете правильную Pydantic-модель в аргументе функции (SpaceshipCreate
).