Ключові відмінності між PUT і POST:
- PUT: використовується для оновлення ресурсу. Передбачається, що дані, які ми надсилаємо, повністю замінюють існуючий об'єкт.
- POST: використовується для створення нового об'єкта або виконання складних операцій на сервері.
Уяви, що PUT — це ніби «переписати повністю», а POST — «додати щось нове».
Приклад сценарію:
У нас є користувач з ID 123, і ми хочемо змінити його ім'я на «Іван Іванов». Це типова задача для PUT-запиту, бо ми оновлюємо вже існуючий запис.
Асинхронна обробка PUT-запитів у FastAPI
FastAPI надає нативну підтримку обробки PUT-запитів за допомогою декоратора @app.put. Давай розберемо все на практиці.
Приклад базового PUT-запиту
Для початку створимо endpoint, що дозволяє оновлювати дані про користувача. Припустимо, у нас є простий словник, що зберігає інформацію про користувачів:
from fastapi import FastAPI
app = FastAPI()
# Приклад даних про користувачів
users = {
1: {"name": "Анна", "age": 25},
2: {"name": "Борис", "age": 30},
}
@app.put("/users/{user_id}")
async def update_user(user_id: int, updated_data: dict):
if user_id not in users:
return {"error": "User not found"} # Проста обробка відсутнього користувача
# Оновлюємо дані користувача
users[user_id] = updated_data
return {"message": "User updated successfully", "data": users[user_id]}
Розберемо шматочок коду:
- Маршрут PUT-запиту:
Ми вказали@app.put("/users/{user_id}"). Це означає, що запити з методом PUT і вказанимuser_idбудуть оброблятися цим endpoint'ом. - Параметри шляху:
user_idвитягується з URL як параметр шляху. - Тіло запиту:
updated_data— це тіло запиту, яке передається клієнтом (наприклад, JSON). Воно містить дані для оновлення. - Оновлюємо дані:
Ми просто замінюємо значення в словникуusers.
Додаємо валідацію даних
Використовувати «сирий» dict — це як жити без тестів: можливо, але складно й небезпечно. На щастя, FastAPI підтримує Pydantic для валідації даних. Давай створимо модель для користувача:
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
Тепер змінимо endpoint, щоб використати цю модель:
@app.put("/users/{user_id}")
async def update_user(user_id: int, updated_data: User):
if user_id not in users:
return {"error": "User not found"}
# Оновлюємо дані користувача, використовуючи Pydantic-модель
users[user_id] = updated_data.dict()
return {"message": "User updated successfully", "data": users[user_id]}
- Тепер
updated_dataавтоматично перевіряється на відповідність моделіUser: ім'я має бути рядком, вік — цілим числом. - У випадку некоректних даних (наприклад, якщо вік вказано рядком), FastAPI автоматично поверне помилку 422 з детальним описом.
Часткове оновлення даних: коли потрібен PATCH?
Може виникнути питання: «А що якщо я хочу змінити тільки ім'я, не чіпаючи вік?». Для цього краще підходить метод PATCH, який дозволяє частково оновити дані. Ми розберемо PATCH пізніше в курсі, а поки зверни увагу, що стандартний PUT-запит передбачає повну заміну даних.
Робота з базою даних: асинхронний приклад
Давай тепер уявимо, що ми використовуємо базу даних для зберігання даних. Як приклад візьмемо SQLite з бібліотекою databases.
Встановлення залежностей:
pip install databases
Приклад асинхронного оновлення в базі даних:
from databases import Database
DATABASE_URL = "sqlite:///./test.db"
database = Database(DATABASE_URL)
# Таблиця користувачів
users_table = """
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER NOT NULL
)
"""
@app.on_event("startup")
async def startup():
await database.connect()
await database.execute(users_table)
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
@app.put("/users/{user_id}")
async def update_user(user_id: int, updated_data: User):
query = "UPDATE users SET name = :name, age = :age WHERE id = :id"
values = {"name": updated_data.name, "age": updated_data.age, "id": user_id}
# Виконуємо асинхронний запит до бази даних
result = await database.execute(query=query, values=values)
if result == 0:
return {"error": "User not found"}
return {"message": "User updated successfully"}
- База даних:
Ми використовуємо SQLite як базу даних і керуємо нею через бібліотекуdatabases. - Асинхронні функції:
Запити до бази даних виконуються асинхронно (await database.execute()). - Оновлення запису:
Ми оновлюємо дані користувача заuser_idза допомогою SQL-запитуUPDATE.
Помилки й виключення при роботі з PUT-запитами
Коли намагаєшся оновити неіснуючий ресурс (наприклад, user_id = 999), сервер має повернути відповідну помилку. У FastAPI це можна зробити через HTTPException:
from fastapi import HTTPException
if user_id not in users:
raise HTTPException(status_code=404, detail="User not found")
Надмірне оновлення
Використання PUT для «часткового» оновлення (наприклад, тільки імені) може призвести до непередбачуваних результатів, якщо не вказати решту полів. Завжди перевіряй, що передані дані відповідають моделі.
Практичне застосування
PUT-запити широко використовуються в реальних проєктах. Наприклад:
- Редагування профілю користувача: оновлення імені, електронної пошти та інших полів.
- Зміна інформації про продукт: оновлення ціни, опису або характеристик.
- Оновлення налаштувань додатку: збереження користувацьких вподобань.
Тепер ти знаєш, як працювати з PUT-запитами, використовувати Pydantic для валідації даних і взаємодіяти з базою даних асинхронно. У наступній лекції перейдемо до видалення даних через DELETE-запити, а поки можеш потренуватися оновлювати свої дані (без порушення GDPR, звісно 😄).
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ