Асинхронні GET-запити — це круто, звісно, але що робити, якщо потрібно більше, ніж просто отримати дані? Іноді потрібно відправити дані на сервер. Ось тут і з'являються POST-запити! Сьогодні розберемо, як їх відправляти, як передавати дані у форматі JSON або FormData і як грамотно обробляти відповіді.
POST-запити — це, по суті, прохання до сервера зробити щось з переданими даними. Наприклад, додати у базу новий об'єкт або створити ресурс.
У чому різниця між GET- та POST-запитами?
GET-запити орієнтовані на читання даних — вони не змінюють стан сервера. POST-запити, навпаки, змінюють стан сервера, оскільки зазвичай використовуються для створення або модифікації ресурсів.
Якщо порівняти їх з повсякденним життям, то GET — це як подивитись меню в ресторані, а POST — це зробити замовлення. Завдання POST-запиту — відправити деталі (наприклад, замовлену страву) на сервер і отримати підтвердження.
Відправка асинхронних POST-запитів
Тепер, коли ми розуміємо теорію, давайте перейдемо до практики. Для відправки POST-запитів будемо використовувати бібліотеку httpx, яка вже стала нашим надійним супутником.
Почнемо з бази: створимо простий асинхронний POST-запит і передамо JSON-дані.
Приклад: відправка JSON-об'єкта
Припустимо, ми хочемо відправити дані користувача на зовнішнє API.
import httpx
from fastapi import FastAPI
app = FastAPI()
# Асинхронний POST-запит
@app.post("/send-data")
async def send_data():
url = "https://jsonplaceholder.typicode.com/posts" # Тестовий доступний API
data = {
"title": "Hello FastAPI",
"body": "FastAPI makes integration so easy!",
"userId": 1
}
async with httpx.AsyncClient() as client:
response = await client.post(url, json=data)
return {"status": response.status_code, "response": response.json()}
Що тут відбувається?
- Створюємо JSON-дані за допомогою Python-словника
data. - Виклик
client.post()відсилає асинхронний запит. Параметрjsonавтоматично серіалізує словник у формат JSON. - Відповідь від сервера (
response) обробляється. Ми повертаємо її статус і JSON-відповідь назад.
Для тестування ми використали https://jsonplaceholder.typicode.com — це популярне тестове API, яке повертає фейкові дані.
Налаштування заголовків і тіла запиту
Іноді API вимагає заголовки (наприклад, Content-Type, Authorization). Ось приклад відправки POST-запиту з додаванням заголовків:
@app.post("/send-data-with-headers")
async def send_data_with_headers():
url = "https://jsonplaceholder.typicode.com/posts"
data = {
"title": "Header Example",
"body": "Including headers in POST request",
"userId": 2
}
headers = {"Authorization": "Bearer some_token_123"}
async with httpx.AsyncClient() as client:
response = await client.post(url, json=data, headers=headers)
return {"status": response.status_code, "response": response.json()}
Тут ми додали заголовок Authorization для аутентифікації. Це звична вимога багатьох API — не забудь уважно прочитати документацію зовнішнього сервісу.
Передача даних у форматі FormData
Іноді зовнішнє API очікує дані у форматі FormData, а не JSON. Це часто буває при обробці завантажених файлів, у формах зворотного зв'язку або при інтеграції зі застарілими системами.
FastAPI використовує Starlette під капотом, а httpx дозволяє легко працювати з формами.
Приклад: відправка FormData
from fastapi import Form
@app.post("/send-form-data")
async def send_form_data():
url = "https://jsonplaceholder.typicode.com/posts"
f_data = {
"field1": "value1",
"field2": "value2"
}
async with httpx.AsyncClient() as client:
response = await client.post(url, data=f_data) # Використовуємо `data` замість `json`
return {"status": response.status_code, "response": response.text}
Ключова відмінність тут у тому, що ми використовуємо параметр data, а не json. httpx перетворює дані у формат application/x-www-form-urlencoded, що відповідає стандарту FormData.
Практичні приклади
Уявімо реальний сценарій. Ми будуємо додаток для управління задачами, і нам потрібно відправити дані нової задачі на зовнішнє API.
@app.post("/tasks")
async def create_task(title: str = Form(...), description: str = Form(None)):
url = "https://yourtaskmanager.com/api/tasks"
data = {
"title": title,
"description": description,
"userId": 42
}
async with httpx.AsyncClient() as client:
try:
response = await client.post(url, json=data)
response.raise_for_status() # Викинути виняток, якщо статус-код не в діапазоні 200-299
except httpx.RequestError as exc:
return {"error": f"An error occurred while requesting: {exc}"}
except httpx.HTTPStatusError as exc:
return {"error": f"HTTP error occurred: {exc.response.status_code}"}
return {"task_id": response.json().get("id"), "message": "Task created successfully"}
При інтеграції з зовнішніми сервісами варто бути готовими до несподіваних збоїв:
- API може тимчасово бути недоступним.
- Ти можеш випадково відправити некоректні дані.
- У API можуть бути обмеження (наприклад, rate limit).
Для обробки таких ситуацій ми використали конструкцію try-except.
Налаштування логування і налагодження
Щоб зрозуміти, що відбувається при помилках, корисно додати логування:
import logging
logging.basicConfig(level=logging.INFO)
@app.post("/log-example")
async def log_example():
url = "https://example.com/api"
data = {"key": "value"}
logging.info("Відправка даних на %s з тілом %s", url, data)
async with httpx.AsyncClient() as client:
response = await client.post(url, json=data)
logging.info("Відповідь сервера: %s", response.status_code)
return response.json()
Підсумковий приклад: реальна інтеграція
Зібрали все в один приклад. Цей ендпоінт:
- Отримує дані від користувача (наприклад, назву і опис задачі).
- Відправляє дані на зовнішнє API.
- Повертає клієнту відповідь від API.
@app.post("/external-task")
async def external_task(title: str = Form(...), description: str = Form(None)):
external_api_url = "https://example.com/api/tasks"
headers = {"Authorization": "Bearer super_secret_token"}
body = {"title": title, "description": description}
async with httpx.AsyncClient() as client:
response = await client.post(external_api_url, json=body, headers=headers)
return {"status": response.status_code, "response": response.json()}
Тепер у тебе є все, що потрібно для відправки POST-запитів! POST відкриває великі можливості для інтеграції FastAPI зі зовнішніми системами — від відправки даних форм до складних взаємодій з RESTful API. Не забувай читати документацію зовнішніх сервісів і тестувати кожну інтеграцію, щоб уникнути несподіваних проблем.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ