- Объяснять части HTTP-запроса и ответа, основные методы и коды состояния
- Отправлять GET-запросы с параметрами и POST-запросы с JSON-телом через
requests - Писать надёжный код с тайм-аутами,
raise_for_statusи исключениями и хранить API-ключи в секрете
Прогноз погоды в телефоне, курсы валют банка, маршрут на карте — все эти данные программы получают с серверов через API (Application Programming Interface). Приложения Educora тоже загружают уроки через API сайта. Веб-API — это простая договорённость: ты отправляешь HTTP-запрос по определённому адресу, а сервер обычно возвращает ответ в JSON. Самый популярный инструмент для этого в Python — библиотека requests.
Коротко об HTTP
Запрос состоит из четырёх частей: метод (что сделать), URL (куда), заголовки (дополнительные сведения: формат, ключ) и тело (отправляемые данные, например JSON). Ответ состоит из кода состояния, заголовков и тела. Часть URL после знака ? — это параметры запроса (query string): ?city=Baku&units=metric.
GET /v1/weather?city=Baku&units=metric HTTP/1.1
Host: api.example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{"city": "Baku", "temp": 24.5, "wind": 7.2, "description": "sunny"}api.example.com — адрес, зарезервированный для примеров в документации; все ответы в уроке иллюстративные.| Метод | Смысл | Пример |
|---|---|---|
GET | получить данные | GET /v1/tasks |
POST | создать новый объект | POST /v1/tasks |
PUT / PATCH | заменить / частично обновить объект | PATCH /v1/tasks/42 |
DELETE | удалить объект | DELETE /v1/tasks/42 |
| Код | Смысл |
|---|---|
| 200, 201, 204 | успех: OK, создано, нет содержимого |
| 301, 302 | перенаправление — смотри другой адрес |
| 400, 401, 403, 404 | ошибка клиента: неверный запрос, нет входа, нет доступа, не найдено |
| 429 | слишком много запросов — лимит превышен, подожди |
| 500, 503 | ошибка сервера, сервис недоступен |
Запросы с requests
Установи библиотеку на компьютер: pip install requests. Python в браузере не может отправлять сетевые запросы, поэтому код этого урока здесь не запускается — попробуй его на своём компьютере. requests.get возвращает объект ответа: status_code, headers, text, json(). Не склеивай параметры с URL вручную: словарь params правильно их кодирует, например «Sumqayıt» превращается в Sumqay%C4%B1t.
import requests
url = 'https://api.example.com/v1/weather'
params = {'city': 'Baku', 'units': 'metric'}
headers = {'Accept': 'application/json'}
response = requests.get(url, params=params, headers=headers, timeout=10)
print(response.status_code)
print(response.url)
print(response.headers['Content-Type'])
data = response.json()
print(data['city'], data['temp'])200 https://api.example.com/v1/weather?city=Baku&units=metric application/json Baku 24.5
response.json() превращает JSON-тело в словарь Python. Вывод — пример: настоящий API вернёт другую температуру.Чтобы создать новый объект, отправляем POST. Аргумент json= превращает словарь в JSON и сам добавляет заголовок Content-Type: application/json. При успешном создании сервер обычно возвращает код 201 и новый объект (с идентификатором).
import requests
new_task = {'title': 'Finish the pandas lesson', 'done': False}
r = requests.post('https://api.example.com/v1/tasks', json=new_task, timeout=10)
print(r.status_code)
print(r.json())
print(r.request.headers['Content-Type'])201
{'id': 42, 'title': 'Finish the pandas lesson', 'done': False}
application/jsonОшибки, тайм-ауты и raise_for_status
Внимание: ответ 404 или 500 для requests — не ошибка, код спокойно продолжает работу. raise_for_status() выбрасывает HTTPError при кодах 4xx и 5xx. Сетевые проблемы — отдельные исключения: Timeout, ConnectionError; все они наследуются от requests.exceptions.RequestException.
import requests
def get_json(url, **params):
try:
r = requests.get(url, params=params, timeout=5)
r.raise_for_status()
return r.json()
except requests.exceptions.Timeout:
print('The server did not answer in time')
except requests.exceptions.HTTPError as e:
print('HTTP error:', e.response.status_code)
except requests.exceptions.RequestException as e:
print('Network problem:', type(e).__name__)
return None
print(get_json('https://api.example.com/v1/weather', city='Atlantis'))HTTP error: 404 None
RequestException), иначе до них никогда не дойдёт очередь.Безопасность API-ключей
Большинство API узнают тебя по ключу (API key, токен). Ключ — как пароль: зная его, кто угодно может отправлять запросы от твоего имени, расходовать твой лимит и даже тратить деньги. Правила:
- Никогда не пиши ключ в коде и не коммить его в Git — храни его в переменной окружения.
- Если используешь файл
.env, добавь его в.gitignore. - Если API позволяет, передавай ключ в заголовке, а не в URL: адреса оседают в журналах и истории браузера.
- Не помещай секретный ключ в код браузерного или мобильного приложения — любой пользователь может его извлечь; отправляй такие запросы через свой сервер.
- Если ключ утёк, немедленно отзови его и создай новый.
# Linux / macOS
export WEATHER_API_KEY='paste-your-key-here'
# Windows PowerShell
$env:WEATHER_API_KEY = 'paste-your-key-here'.env.import os
import requests
api_key = os.environ.get('WEATHER_API_KEY')
if not api_key:
raise SystemExit('Set the WEATHER_API_KEY environment variable first')
session = requests.Session()
session.headers.update({'Authorization': f'Bearer {api_key}'})
r = session.get('https://api.example.com/v1/weather', params={'city': 'Baku'}, timeout=10)
r.raise_for_status()
print(r.json()['description'])sunny
Session сама добавляет его в заголовок каждого запроса. Точное имя заголовка (Authorization, X-API-Key и т. п.) указано в документации API.Главное
- HTTP-запрос: метод, URL, заголовки, тело; ответ: код состояния, заголовки, тело (часто JSON).
- GET читает, POST создаёт, PUT/PATCH обновляют, DELETE удаляет; 2xx — успех, 4xx — ошибка клиента, 5xx — ошибка сервера.
requests.get(url, params=..., headers=..., timeout=...)иrequests.post(url, json=...); результат — черезr.json().- Всегда передавай
timeoutи вызывайraise_for_status(); перехватывай исключения от частных к общему. - API-ключ хранится в переменной окружения, передаётся в заголовке и никогда не попадает в Git; утёкший ключ отзывают.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.
requests.get(...)?