CRUD — це абревіатура, яка розшифровується як Create, Read, Update і Delete, тобто "Створити, Прочитати, Оновити, Видалити". Всі ці операції лежать в основі кожного додатка, який працює з даними. Хочеш записати користувача в базу? Це Create. Потрібно показати список товарів? Read. А якщо користувач вирішив оновити свій номер телефону? Update. Ну а видалення даних (іноді з сумом, як прощання) — це Delete.
На співбесідах на позицію Python-розробника вас обов'язково спитають про реалізацію CRUD API. У реальному житті такі API використовуються для управління об'єктами, взаємодії з базою даних і побудови надійних систем. На практиці API, які ми створюємо, майже завжди складаються з подібних операцій.
Сьогодні ми зробимо міні-додаток на FastAPI, яке буде керувати списком книг. Кожна книга буде характеризуватися такими атрибутами:
id— унікальний ідентифікатор книги (ціле число).title— назва книги (рядок).author— автор (рядок).year— рік публікації (ціле число).
Налаштування проєкту
Спершу переконайся, що в тебе встановлені FastAPI, Uvicorn і Pydantic. Якщо ні — виправимо це командою:
pip install fastapi uvicorn pydantic
Створи структуру проєкту:
crud_app/
├── main.py
└── models.py
У файлі main.py буде описана логіка нашого додатка, а models.py — місце, де ми визначимо наші Pydantic-моделі.
Моделювання даних
Почнемо з визначення книги як об'єкта. Відкрий models.py і створи наступне:
from pydantic import BaseModel
from typing import Optional
# Модель даних для книги
class Book(BaseModel):
id: int
title: str
author: str
year: int
# Модель для оновлення книги (часткове оновлення)
class BookUpdate(BaseModel):
title: Optional[str] = None
author: Optional[str] = None
year: Optional[int] = None
Ми визначили дві моделі:
Book— повна модель книги.BookUpdate— дозволяє оновлювати лише частину полів об'єкта.
Реалізація CRUD-операцій
Тепер переходимо до головного файлу main.py. Почнемо з підключення базових бібліотек і ініціалізації FastAPI:
from fastapi import FastAPI, HTTPException
from models import Book, BookUpdate
app = FastAPI()
# Сховище даних
books = [] # В цій реалізації використовуємо список для зберігання книг.
Створення книги (Create)
Ми створимо endpoint, який приймає дані книги в форматі JSON, валідирує їх і додає книгу до списку.
@app.post("/books/", response_model=Book)
async def create_book(book: Book):
# Перевіряємо, чи вже є книга з таким id
for existing_book in books:
if existing_book.id == book.id:
raise HTTPException(status_code=400, detail="Книга з таким ID вже існує")
books.append(book)
return book
Отримання списку книг (Read)
Тепер зробимо endpoint для читання списку всіх книг.
@app.get("/books/", response_model=list[Book])
async def get_books():
return books
Або окремої книги за id:
@app.get("/books/{book_id}", response_model=Book)
async def get_book(book_id: int):
for book in books:
if book.id == book_id:
return book
raise HTTPException(status_code=404, detail="Книга не знайдена")
Оновлення книги (Update)
Оновлення книги буде оброблятися через PUT-запит, а часткове оновлення реалізоване з використанням моделі BookUpdate.
@app.put("/books/{book_id}", response_model=Book)
async def update_book(book_id: int, book_update: BookUpdate):
for book in books:
if book.id == book_id:
# Оновлюємо тільки ті поля, які були передані
if book_update.title is not None:
book.title = book_update.title
if book_update.author is not None:
book.author = book_update.author
if book_update.year is not None:
book.year = book_update.year
return book
raise HTTPException(status_code=404, detail="Книга не знайдена")
Видалення книги (Delete)
Для видалення книги також додамо endpoint:
@app.delete("/books/{book_id}", response_model=dict)
async def delete_book(book_id: int):
for book in books:
if book.id == book_id:
books.remove(book)
return {"message": "Книга успішно видалена"}
raise HTTPException(status_code=404, detail="Книга не знайдена")
Валідація даних і обробка помилок
FastAPI вже автоматично робить багато роботи за нас завдяки Pydantic. Якщо дані не відповідатимуть моделі, API поверне зрозуміле повідомлення про помилку. Приклад:
{
"detail": [
{
"loc": ["body", "title"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
У випадку користувацьких помилок, таких як спроба створити книгу з уже існуючим ID, використовуємо HTTPException.
Швидка інтеграція з базою даних (опційно)
Наразі наші дані зберігаються в пам'яті (список books). Це зручно для швидких експериментів, але непридатне для реальних проєктів. Підключимо базу даних SQLite.
Встанови SQLAlchemy і aiosqlite:
pip install sqlalchemy aiosqlite
Винесемо моделі в models.py і створимо SQLAlchemy ORM:
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
# Модель книги для роботи з базою даних
class BookDB(Base):
__tablename__ = "books"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
author = Column(String)
year = Column(Integer)
# Створюємо SQLite базу даних
DATABASE_URL = "sqlite:///./books.db"
engine = create_engine(DATABASE_URL)
Base.metadata.create_all(bind=engine)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Тепер в CRUD-endpoint'ах ти будеш використовувати SessionLocal для взаємодії з базою. Наприклад, замість додавання в список books використовуй базовий SQL-запит:
db = SessionLocal()
db.add(new_book)
db.commit()
Цей крок виводить твою реалізацію на новий рівень, дозволяючи працювати з великими обсягами даних.
Ось і все! Ми створили повноцінний CRUD API, який можна далі покращувати і адаптувати під потреби твого проєкту. Це потужний старт для побудови твоїх додатків!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ